学了python之后一直在给自己找点儿什么需求练练手,爬虫是学python最快的途径,就想着爬点豆瓣电影的数据吧,在经过了一系列重复造轮子之后,决定体验一下scrapy。
scrapy的架构图:
1、引擎(ScrapyEngine): 用来处理整个系统的通讯,数据流处理, 触发事务(框架核心)。
2、调度器(Scheduler): 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址。
3、下载器(Downloader): 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)。
4、爬虫(Spiders): 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
5、项目管道(Pipeline): 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
6、下载器中间件(Downloader Middlewares): 位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。
7、爬虫中间件(Spider Middlewares): 介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。
8、调度中间件(Scheduler Middewares): 介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应
scrapy流程:
1.Spider将初始url告诉Engine,Engine将url添加到调度器的请求队列中
2.Engine从调度器队列中拿到下一个要请求的url,交给下载器(下载器中间件可以设置代理之类。。),下载器下载网页内容,交还给引擎
3.Engine将从下载器拿到的网页内容,交给spider,spider爬取所需要的内容,生成item交还给Engine,如果需要继续爬取,将新的url告诉Engine,并添加到调度器的请求队列中
4.pipeline 从Engine拿到爬取的实体进行处理
python&scrapy安装:
开始
创建项目:
scrapy startproject 项目名称
目录介绍:
.cfg 项目配置文件 定义了项目配置文件路径,部署信息等内容
items.py 定义item数据结构的地方
settings.py 项目的设置文件,定义项目的全局设置
生成spiders文件:
在spiders目录中进入命令行输入 scrapy genspider 爬虫名 要爬取的域名
刷新项目文件目录
spider文件中:
name : 爬虫的名称
start_urls : 为初始爬虫目录,就是第一次爬取的地址url
执行爬虫文件 :
scrapy crawl 爬虫名称
爬取豆瓣电影网站内容
在项目磁盘目录下打开命令行输入
scrapy startproject douban_demo
生成项目文件
修改settings.py文件中USER_AGENT和ROBOTSTXT_OBEY:不然请求会被拦截
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
ROBOTSTXT_OBEY = False
在spiders目录中进入命令行输入
scrapy genspider douban_spider movie.douban.com
之后会在spiders目录中生成一个douban_spider.py 的文件,修改start_urls:
start_urls = ['http://movie.douban.com/top250']
打开页面,我们接下来要抓取这些数据
在items.py中创建我们的数据模型:
class DouBanItem(scrapy.Item):
#电影编号
movie_num = scrapy.Field()
#电影封面地址
movie_imgurl = scrapy.Field()
#电影名称
movie_name = scrapy.Field()
#电影参与人员
movie_person = scrapy.Field()
#电影评分
movie_grade = scrapy.Field()
#电影口号
movie_slogen = scrapy.Field()
douban_spider.py中 的 parse方法,就是我们写爬虫代码的地方
检查页面,查看页面标签详情,可以看到页面的标签结构
爬取数据:
movies = response.css('div.item')
for movie in movies:
movie_num = movie.css('em::text').extract_first()
movie_imgurl = movie.css('img::attr(src)').extract_first()
movie_name = movie.css('.title::text').extract_first()
movie_person = movie.css('.bd p::text').extract_first()
movie_grade = movie.css('.rating_num::text').extract_first()
movie_slogen = movie.css('.inq::text').extract_first()
doubanItem = DouBanItem()
doubanItem['movie_num'] = movie_num
doubanItem['movie_imgurl'] = movie_imgurl
doubanItem['movie_name'] = movie_name
doubanItem['movie_person'] = movie_person
doubanItem['movie_grade'] = movie_grade
doubanItem['movie_slogen'] = movie_slogen
将爬取到的数据加入pipline管道
yield doubanItem
将数据写入txt文本文件
with open('movie_info.txt','a+',encoding='utf-8') as f:
f.write(movie_num+" : "+movie_name+" : \t"+movie_grade+"\n")
f.write('封面图片地址 : '+movie_imgurl+'\n')
f.write('参与人员 : '+movie_person+'\n')
f.write(movie_slogen+"\n")
f.write('\n-----------------------------------------\n')
使用a+追加方式,编码使用utf-8,打开文本文件,往里写入
继续爬取下一页数据:
next_page = response.css('span.next a::attr(href)').extract_first()
if next_page is not None:
realUrl = "http://movie.douban.com/top250"+next_page
realUrl = response.urljoin(realUrl)
yield scrapy.Request(realUrl,callback=self.parse)
根据css找到下一页按钮中的地址,这个页面是需要拼接host地址,如果 is not None 表示还有下一页,
urljoin(url)将地址添加到调度器请求队列中,scrapy.Request(realUrl,callback=self.parse)之情请求,设置回调使用当前parse方法作为返回数据的处理方法
用爬取到的数据,生成json文件
在命令行中(可以使用pycharm中的Terminal命令行)执行爬虫文件
scrapy crawl douban_spider -o douban.json
'douban_spider'是douban_spider.py中name字段的值
执行完本地就会生成一个json文件
用爬取到的数据,生成csv格式文件
在命令行中(可以使用pycharm中的Terminal命令行)执行爬虫文件
scrapy crawl douban_spider -o douban.csv
'douban_spider'是douban_spider.py中name字段的值
执行完本地就会生成一个csv文件
爬取数据存储MongoDB
首先在settings.py文件中打开 pipeline开关,并在最后面配置mongodb
ITEM_PIPELINES = {
'scrapy_demo.pipelines.ScrapyDemoPipeline': 300,
}
mongo_host = '127.0.0.1'
mongo_port = 27017
mongo_db_name = 'douban'
mongo_db_collection = 'douban_movie
在pipelines.py中编写代码
首先导入settings中的mongodb配置和mongodb
import pymongo
from scrapy_demo.settings import mongo_db_collection,mongo_db_name,mongo_host,mongo_port
在构造函数中传入配置参数:
def __init__(self):
# 端口号
port = mongo_port
# 基地址
host = mongo_host
# 数据库名
dbname = mongo_db_name
# 表名
sheetname = mongo_db_collection
# 创建client
client = pymongo.MongoClient(host=host,port=port)
# 指定数据库
mydb = client[dbname]
# 找到表
self.post = mydb[sheetname]
在process_item方法中进行数据插入的编写
def process_item(self, item, spider):
# 将模型转化为字典
data = dict(item)
# 将字典数据插入mongodb
self.post.insert(data)
return item
运行之后就可以在数据库中看到咱们已经添加了数据
对爬虫进行伪装
设置代理ip
为了不让要爬取的网站发现我们的爬取动作,需要对爬虫进行一些伪装,
我们可以通过下载器中间件(Downloader Middlewares)对我们的请求进行伪装
将settings.py中的DOWNLOADER_MIDDLEWARES配置打开(543为优先级,数字越小,优先级越高)
DOWNLOADER_MIDDLEWARES = {
'scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware': 543,
}
在middlewares.py文件中进行编写
创建一个中间件:
class DoubanProcess(object):
def process_request(self,request,spider):
request.meta['proxy'] = '你的代理ip地址'
# 需要登录的话-因为加密需要byte类型,所以需要在前面加b
name_pwd = b'用户名:密码'
# 对用户名密码加密
encode_name_pwd = base64.b64decode(name_pwd)
# 设置http头
request.headers['Proxy-Authorization'] = 'Bisic ' + encode_name_pwd.decode()
将你的中间件添加到settings.py的DOWNLOADER_MIDDLEWARES配置中
DOWNLOADER_MIDDLEWARES = {
# 'scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware': 543,
'scrapy_demo.middlewares.DoubanProcess': 543,
}
设置随机User-Agent
在middlewares.py文件中进行编写
创建一个中间件:
class DoubanUserAgent(object):
def process_request(self,request,spider):
# user-agent列表
USER_AGENT_LIST = [
'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',
'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',
'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',
'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',
'iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:5.0) Gecko/20100101 Firefox/5.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20120813 Firefox/16.0',
'Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)',
'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'
]
# 使用random随机从列表中选择一个user-agent
agent = random.choice(USER_AGENT_LIST)
# 修改请求头
request.headers['User_Agent'] = agent
将user-agent中间件添加到 settings.py的DOWNLOADER_MIDDLEWARES配置中(优先级不能相同)
DOWNLOADER_MIDDLEWARES = {
# 'scrapy_demo.middlewares.ScrapyDemoDownloaderMiddleware': 543,
'scrapy_demo.middlewares.DoubanProcess': 543,
'scrapy_demo.middlewares.DoubanUserAgent': 544,
}