Github项目地址:https://github.com/xylon666/Scrapy
Scrapy框架,简单来说就是把爬虫各功能模块分割开来,分别负责相应的功能,让我们通过简单的学习和实践来使用他
框架示意图:
架构分析:
Scrapy Engine
:Scrapy引擎。负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。Scheduler
:调度器。从Scrapy Engine接受请求(requests)并排序列入队列,并在引擎再次请求时返回。用它来决定下一个抓取的网址是什么,同时去除重复的网址。Downloader
:下载器。抓取网页并将网页内容返还给Spiders。建立在twisted异步模型。Spiders
:爬虫。用户自定义的类,主要用来解析网页,提取Items,发送url跟进等新请求等。Item Pipelines
:管道。主要用来处理Spider解析出来的Items,进行按规则过滤,验证,持久化存储(如数据库存储)等Downloader Middlewares
:下载中间件。位于Scrapy Engine和Downloader之间,主要是处理Scrapy引擎与下载器之间的请求及响应。Spider Middlewares
:爬虫中间件。位于Scrapy Engine和Spiders之间,主要工作是处理Spiders的响应输入和请求输出。Scheduler Middlewares
:调度中间件。位于Scrapy Engine和Scheduler之间。主要工作是处理从Scrapy Engine发送到Scheduler的请求和响应。
所需环境:
编译器:Pycharm
第三方库:scrapy
Scrapy相关依赖库:
lxml
parsel
w3lib
twisted
cryptography
pyOpenSSL
均可通过pip install 安装
实践目标:
使用Scrapy框架爬取豆瓣电影排行版Top250
创建项目:
选择创建项目的文件路径,如在D盘创建一个文件夹"Douban_Scrapy"
然后运行cmd,cd到该目录
d:
cd D:\Douban_Scrapy
创建项目:
scrapy startproject douban
运行后我们会发现在该目录下多了几个文件,在Pycharm中打开:
对比文章开头的框架示意图,简单介绍下他们的功能
spiders目录:编写爬虫代码的主体
items:存放获取数据的相关元素
middlewares:定义爬虫过程中的操作
pipelines:定义存储信息时的操作,例如将数据传入ManggoDB或MySQL
setting:顾名思义,用来定义我们的各种配置,比如请求头信息等
初始化爬虫:
运行cmd,cd到爬虫project的spiders目录,执行:
scrapy genspider douban_spider movie.douban.com
这样一个爬虫模板就自动建好了
由于需要多次运行cmd来执行scrapy命令,我们可以通过Pycharm直接在编译器内来实现这一过程
在spiders目录新建main.py:
from scrapy import cmdline
cmdline.execute('scrapy genspider douban_spider movie.douban.com'.split())
运行后无需通过cmd就能执行命令了
再修改一下setting配置:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
#伪装头
ROBOTSTXT_OBEY = False
#忽略网页的爬虫规则
DOWNLOAD_DELAY = 0.5
#下载延时
再来看一下要爬的内容:
我们通过该页面可以获取到的信息有:排名,电影名,星级,评价人数,描述
根据爬取对象编辑items.py文件
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class DoubanItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 排名
movie_num = scrapy.Field()
# 电影名称
movie_name = scrapy.Field()
# 星级
star = scrapy.Field()
# 评价人数
value = scrapy.Field()
# 描述
describle = scrapy.Field()
编辑爬虫代码douban_spider.py:
# -*- coding: utf-8 -*-
import scrapy
class DoubanSpiderSpider(scrapy.Spider):
#爬虫名称
name = 'douban_spider'
#爬虫允许抓取的域名
allowed_domains = ['movie.douban.com']
#获取数据传给调度器的地址
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
print(response.text)
执行命令:
在cmd中对应目录下
scrapy crawl douban_spider
或在Pycharm中spiders目录下新建main.py
from scrapy import cmdline
cmdline.execute('scrapy crawl douban_spider'.split())
执行结果,可以发现成功获取到了豆瓣网页源代码
分析页面:
网页源代码已获取,再来看要爬取的内容:
电影信息都在div class='"article"//ol class="grid_view"下的<li>标签内,通过xpath对其解析获取:
# -*- coding: utf-8 -*-
import scrapy
class DoubanSpiderSpider(scrapy.Spider):
name = 'douban_spider'
allowed_domains = ['movie.douban.com']
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
for item in movie_list:
print(item)
如果你不知道xpath,推荐阅读:xpath语法
获取该页面所有电影信息后,从中提取出我们需要的部分
导入模型文件:
from ..items import DoubanItem
从我们刚刚获得的电影信息中,根据节点信息获取电影排名:
for item in movie_list:
douban_item = DoubanItem()
#模型初始化
douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
#从当前标签起始,访问目标标签获取文本信息,将其写入movie_num
以此类推,获取后面的内容
for item in movie_list:
douban_item = DoubanItem()
douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
print(douban_item)
yield douban_item
#将返回结果压入item Pipline进行处理
运行结果(红色信息是正常情况):
循环获取当前页面所有电影信息后,我们需要访问下一页继续获取数据,右键检查“后页”
根据标签信息,拼接前缀获取完整链接并访问下一页
next_link = response.xpath("//span[@class='next']/link/@href").get()
if next_link:
yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)
通过输出结果可以看到成功访问到了最后一页
完整代码:
# -*- coding: utf-8 -*-
import scrapy
from ..items import DoubanItem
class DoubanSpiderSpider(scrapy.Spider):
#爬虫名称
name = 'douban_spider'
#爬虫允许抓取的域名
allowed_domains = ['movie.douban.com']
#获取数据传给调度器的地址
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
for item in movie_list:
douban_item = DoubanItem()
douban_item['movie_num'] = item.xpath(".//div[@class='item']//em/text()").get()
douban_item['movie_name'] = item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").get()
douban_item['star'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[2]/text()").get()
douban_item['value'] = item.xpath(".//div[@class='bd']/div[@class='star']/span[4]/text()").get()
douban_item['describle'] = item.xpath(".//div[@class='bd']/p[@class='quote']/span/text()").get()
print(douban_item)
yield douban_item
#将返回结果压入item Pipline进行处理
next_link = response.xpath("//span[@class='next']/link/@href").get()
if next_link:
yield scrapy.Request('http://movie.douban.com/top250' + next_link, callback=self.parse)
保存文件:
保存为csv文件:
scrapy crawl douban_spider -o movielist.csv
保存为json文件:
scrapy crawl douban_spider -o movielist.json
注意:使用excel打开csv文件时,常常会发生乱码,这是由于csv数据用逗号分隔,而excel通过ANSI解码导致的
解决方法:
在爬虫文件中添加以下代码,预先设置csv文件的编码格式为UTF8-BOM
import codecs
with codecs.open('movielist.csv','wb+') as f:
f.write(codecs.BOM_UTF8)
结果展示: