本页代码可以在这里下载。
如果无法启动Scrapy移步这里。
PySpider和Scrapy的区别:
前者提供了WebUI,代码的编写、调试都是在WebUI中继续,而后者的原生不具备这个功能,采用代码和命令行操作,但可以通过对接Portia实现可视化配置。
前者调试非常方便,WebUI操作便捷直观。后者则是使用parse命令进行调试。
前者支持PhantomJS来进行JS渲染,而后者可以对接Scrapy-Splash组件,这个需要格外配置。
前者内置pyquery作为选择器,而后者对接XPath和CSS选择器。
前者可扩展程度不足,可配置化程度不高。后者可以通过对接Middleware、Pipeline、Extension 等组件实现非常强大的功能,且模块之间耦合程度低,可扩展程度极高。
Scrapy基本介绍:
Scrapy是一个基于Twisted的异步处理框架,是纯Python实现的爬虫框架,其架构清晰,米块之间的耦合程度极低,可扩展性极强,可以灵活完成各种需求。
它可以分为以下几部分:
Engine:引擎,处理整个系统的数据流处理、出发事物,是整个框架的核心。
Item:项目,它定义了爬取结果的数据结构,爬取的数据会被赋值成该Item对象。
Scheduler:调度器,接受引擎发过来的请求并将其加入队列中,在引擎再次请求的时候将请求提供给引擎。
Downloader:下载器,下载网页内容,并将内容返回给蜘蛛。
Spider:蜘蛛,其内定义了爬取的逻辑和网页的解析规则,他主要负责解析响应并生成提取结果和新的请求。
Item Pipeline:项目管道,负责处理由蜘蛛从网页中抽取的项目,它主要任务是清洗、验证和存储。
Downloader Middlewares:下载器中间件,位于引擎和下载器之间的钩子框架,主要处理引擎和下载器之间的请求和相应。
Spider Middlewares:蜘蛛中间件,位于引擎和蜘蛛之间的钩子架构,主要处理蜘蛛输入的响应和输出的结果及新的请求。
创建Scrapy:
我们以爬取http://quotes.toscrape.com/ 为例
在命令行中输入scrapy startproject tutorial
其中scrapy startproject是固定启动命令 tutorial是工程名。
创建完成之后当前目录下会多一个tutorial文件夹。
然后进入tutorial目录下,命令行输入:
scrapy genspider quotes quotes.toscrape.com
genspider命令中第一个参数是文件名,第二个参数是URL
创建Spider的子类,用来抓取网页中的内容。
运行结束之后我们看到spiders文件下多了一个quotes.py
其中代码:
# -*- coding: utf-8 -*- import scrapy class QuotesSpider(scrapy.Spider): name = 'quotes' allowed_domains = ['quotes.toscrape.com'] start_urls = ['http://quotes.toscrape.com/'] def parse(self, response): pass
这里有三个属性:name、allowed_domains 和start_urls,还有一个方法parse。
name:没一个项目唯一的名字,用来区分不同的Spider
allowed_domains:允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉。
start_urls:它包含了Spider在启动时爬取的url列表,初始请求是由它来定义的。
parse:他是Spider的一个方法。默认情况下,被调用start_urls里面的链接构成的请求完成下载执行后,返回响应就会作为唯一的参数传递给这个函数。该方法负责解析返回的响应、提取数据或进一步生成要处理的请求。
创建item:
保存爬去数据的容器,使用方法和字典类似,但是多了保护机制,可以避免拼写错误或者定义字段错误。
items.py
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class TutorialItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() text = scrapy.Field() author = scrapy.Field() tags = scrapy.Field()
quotes.py 下 parse() 方法
然后我们更改quotes.py,注意这里下一页是相对链接,需要使用reljoin转换成绝对链接。
然后处理信息过滤:
# -*- coding: utf-8 -*- import scrapy from tutorial.items import TutorialItem class QuotesSpider(scrapy.Spider): name = 'quotes' allowed_domains = ['quotes.toscrape.com'] start_urls = ['http://quotes.toscrape.com/'] def parse(self, response): quotes = response.css('.quote') for quote in quotes: item = TutorialItem() item['text'] = quote.css('.text::text').extract_first() item['author'] = quote.css('.author::text').extract_first() item['tags'] = quote.css('.tags .tag::text').extract() yield item # 获取下一页链接 next = response.css('.pager .next a::attr("href")').extract_first() # 处理绝对链接 url = response.urljoin(next) yield scrapy.Request(url=url, callback=self.parse)
然后在命令行输入: scrapy crawl quotes
输出爬取结果:
输出到文件:
命令行输入:
scrapy crawl quotes -o quotes.json
这里是输出一个json文件,同样还可以输出.csv、.xml等许多格式。
输出到数据库:
我们可以使用Item Pipeline把数据保存到数据库。
我们可以使用Item Pipeline来做以下操作:
清理HTML数据。
验证爬取数据,检查爬取文字。
查重并丢弃重复内容。
将爬取结果保存到数据库中。
要实现Item Pipeline,只需要定义一个类并实现process_item()方法即可。
修改项目中的pipelines.py文件:
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html from scrapy.exceptions import DropItem import pymongo class TutorialPipeline(object): def __init__(self): self.limit = 50 def process_item(self, item, spider): if item['text']: if len(item['text']) > self.limit: # rstrip 删除结尾空格 item['text'] = item['text'][0:self.limit].rstrip() + '...' return item else: return DropItem('Missing Text') class MongoPipeline(object): def __init__(self, mongo_uri, mongo_db): self.mongo_uri = mongo_uri self.mongo_db = mongo_db @classmethod def from_crawler(cls, crawler): return cls( mongo_uri=crawler.settings.get('MONGO_URI'), mongo_db=crawler.settings.get('MONGO_DB') ) def open_spider(self, spider): self.client = pymongo.MongoClient(self.mongo_uri) self.db = self.client[self.mongo_db] def process_item(self, item, spider): name = item.__class__,__name__ self.db[name].insert(dict(item)) return item def close_spider(self,spider): self.client.close()
这里我们在构造方法中定义了限制长度50,实现了process_item(),其参数是item和spider,首先该方法判断item的text属性是否存在,如果不存在抛出异常,如果存在,在判断长度是否大于50,如果大于,那就阶段然后拼接省略号,再将item返回。
然后定义了一个类MongoPipeline来保存进数据库:
from_crawler();一个类方法,用@classmethod标识,是一种依赖注入的方式,他的参数就是crawler,通过crawler我们可以拿到全局配置的每个配置信息。在全局配置settings.py中,我们可以定义MONGO_URI 和 MONGO_DB 来指定MongoDB 连接需要的地址和数据库名。即这个方法就是用来获取settings.py中的配置的。
open_spider();当Spider开启时,这个方法被调用,主要进行一些初始化操作。
close_spider();当Spider关闭时,这个方法被调用,主要进行关闭数据库操作。
process_item();执行数据插入操作。
然后在settings.py中添加配置信息:
ITEM_PIPELINES = { 'tutorial.pipelines.TutorialPipeline': 300, 'tutorial.pipelines.MongoPipeline': 400 } MONGO_URI = 'localhost' MONGO_DB = 'Test'
最后重新运行爬虫,数据库输出如下:
Selector 的用法:
selector是Scrapy提供的自己的数据提取方法,它是基于lxml来构建的,支持XPath选择器、CSS选择器以及正则表达式,功能全面,解析速度和准确度非常高。
我们可以直接利用Selector 这个类来构建一个选择器对象,然后调用xpath()、css()等来提取数据。
Spider 的用法:
在Scrapy爬虫项目中,最核心的类就是Spider类了,它定义了如何爬取某个网站的流程和解析方式。
创建爬虫:
在已经创建好项目之后,输入
scrapy genspider name url 即可创建一个爬虫,文件会存入spiders中
1.name
爬虫名字,必须唯一。
2.allowed_domains
允许爬取的域名,是可选配置
比如这里
如果URL跳出该网站则不被爬取。
3.start_urls
其实URL列表,即从当前列表开始爬取。
4.custom_setting
是一个字典, 是专属于本Spider类的配置,此设置会覆盖项目全局的设置。
我们可以在项目文件中看到settings文件,这个文件中存放了许多默认的值,比如默认请求头等,如果把默认请求头注视掉将无法访问网站,但是我们可以在方法中使用custom_setting,来覆盖或者代替setting,使爬虫可以访问目标网站。
# -*- coding: utf-8 -*- import scrapy class ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = ['www.zhihu.com'] start_urls = ['http://www.zhihu.com/'] custom_settings = { 'DEFAULT_REQUEST_HEADERS': { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', } } def parse(self, response): pass
5.crawler
它由from_crawler方法设置,代表的是本Spider类对应的Crawler对象,利用它我们可以获取项目的一些配置信息,如piplines中:
6.start_requests
此方法用于声称初始请求,他必须返回一个可迭代对象,我们可以使用此方法更改访问方式。
例如我们如果不加这个方法访问post的时候,则会返回异常状态码,但是加了该方法并加了一个解析函数,我们可以看见正确的访问了页面,并正确执行了解析函数。
7.make_resquests_from_url
更改回调函数(默认parse)
# -*- coding: utf-8 -*- import scrapy class BaiduSpider(scrapy.Spider): name = 'baidu' allowed_domains = ['www.baidu.com'] start_urls = ['http://www.baidu.com/'] def make_requests_from_url(self, url): return scrapy.Request(url=url, callback=self.parse_index) def parse_index(self, response): print("Baidu", response.status) def parse(self, response): pass
Item pipeline 的用法:
项目管道,数据清洗、检查爬取字段,查重并存入数据库。
我们可以自定义item pipeline,只需要实现指定的方法,其中必须要实现的一个方法是process_item(item, spider)
其中
item 是Item对象,即被处理的对象,由parse()生成。
spider是Spider对象,即生成该item的Spider。
还有一些其他的方法:
open_spider(spider):Spider开启的时候被调用。
close_spider(spider):Spider关闭的时候被调用。
from_crawler(cls,crawler):是一个类方法,用@classmethod进行标识,是一种依赖注入的方式。一般来获取一些配置信息,设置等。
我们可以在构造函数中设置一个集合的set()来进行数据去重,其中set()返回的就是数据的集合
self.ids_seen = set()
我们还可以在setting中设置优先级(数字(0~1000)越小,优先级越高)来使用item pipeline
ITEM_PIPELINES = { 'tutorial.pipelines.TutorialPipeline': 300, 'tutorial.pipelines.MongoPipeline': 400 }
.
0 条评论