玩scrapy 时,一直看着这张图就ok.
scrapy需要的基础 : lxml ( xpath) , 关键字 yield ( 生成器) . 生成器我的博客中有很多文章.可以自己去找 .
下面先说一下scrapy的全貌:
一个最简单的Spider : 基本上你用scrapy创建的跟我的差不多.
class ChoutiSpider(scrapy.Spider):
name = 'chouti'
allowed_domains = ['chouti.com']
start_urls = ['https://dig.chouti.com/']
def parse(self, response):
print("return : ",response.url , response.meta)
yield response.meta
先说一下大致的流程:
1 . Spider.start_requests 读取 start_urls 每次yield 一个Request , 这个Request 将被传递到(每个)Spider中间件(Spider middlewares,看图) , 在Spider中间件中执行 process_start_requests 处理( yield )每个Request .接下来到了调度器中, 由调度器传递给 (每个) 下载中间件(Downloader middlewares) , 每个下载中间件将调用 process_request (这一步往往我们会用的比较多,
比如修改Header , User-Agent, Proxy 等等) ,之后就真正去下载网页了.
2. 等到网页下载完成后, 将回到(每个) 下载中间件的 process_response ,意思是返回前你还需要对response做点什么.默认直接返回。接着再次通过 (每个)Spider中间件 的 process_spider_input ,意思是你还有次机会能处理response .最后回到 parse函数.
3.在上面的代码中有一句yield response.meta 这一步的流程是 : 通过(每个)Spider中间件的 process_spider_output 传递给
(每个) pipelines (常常用于过滤/清洗数据, 以及保存到文件或数据库) 的 process_item . 附注: item 你可以完全把他当成dict使用.
这3个步骤基本就是Scrapy的执行流程. 上面的叙述中我都使用了(每个)的意思是, 这些中间件和pipelines 都可以创建多个.
然后在settings.py 中指定其调用顺序.
比方有这么一个下载中间件:
#代理中间件 属于下载中间件
class xProxy(HttpProxyMiddleware):
def __init__(self,encodeing):
super().__init__(encodeing)
self.PROXIES = ['http://183.207.95.27:80', 'http://111.6.100.99:80',
'http://60.31.239.166:3128', 'http://114.55.31.115:3128']
def process_request(self, request, spider):
import random
request.meta['proxy'] =random.choice(self.PROXIES)
super().process_request(request,spider)
#指定User-agent 中间件 属于下载中间件
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
class RandomUserAgent:
def __init__(self):
self.user_agents = ['MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"]
def process_request(self, request, spider):
print('->RandomUserAgent process_request')
import random
request.headers['User-Agent'] = random.choice(self.user_agents)
内部2个类, 一个用于选择代理, 一个用于选择USER-AGENT . 他们2 都属于下载中间件.
因此 . 在setting.py 中指定这样的顺序:
# DOWNLOADER_MIDDLEWARES = {
# 'testscrapy.middlewares.RandomUserAgent': 540,
# 'testscrapy.proxymiddleware.xProxy':541
# }
那么RandomUserAgent中的process_request 将先调用. 而后将调用xProxy.process_request.
这种顺序通用于scrapy中的各个组件. 比如Spider中间件, pipelines.
在scrapy 中你会发现有很多依赖创建的函数 : from_crawler / from_settings 类方法 ,以及process_xxx的处理函数. 大多数情况下,在后期编写过程中你也发现这些. 最后说一下扩展. 扩展依赖信号.
比如:
from scrapy import signals
from scrapy.crawler import Crawler
class Extention :
def __init__(self,crawler):
self.crawler = crawler
self.settings = crawler.settings
#scrapy将使用 from_crawler 来依赖创建对象
@classmethod
def from_crawler(cls, crawler):
#创建这个扩展
obj = cls(crawler)
#通过信号来调用
#如果spider 打开时
crawler.signals.connect(obj.opened , signal=signals.spider_opened)
#如果spider 结束
crawler.signals.connect(obj.closed,signal=signals.spider_closed)
#如果spider 有一item 被pipeline接受了
crawler.signals.connect(obj.item_pushed,signal=signals.item_scraped)
return obj
def item_pushed(self,item,spider,response):
print('Extention item pushed : ', item, spider.name ,response)
def opened(self,spider):
print('Extention opened name:%s'%spider.name)
def closed(self,spider):
print('Extention closed name:%s'%spider.name)
到此为止. 基本的scrapy全貌已经说完;
正式的教程:
class ChoutiSpider(scrapy.Spider):
name = 'chouti' # 爬虫名字 , 全局唯一
allowed_domains = [] #允许的域名, 空为都可以爬取,如果填上chouti.com,则只能爬chouti
start_urls = ['https://dig.chouti.com/'] #父类start_requests将循环这个变量
#当然你可以修改父类的start_requests
#源码类似于
# def start_requests(self):
# for url in self.start_urls:
# yield url
def parse(self, response): #访问完成后将回到这个默认函数中
print("return : ",response.url , response.meta)
# yield response.meta
#call_back 指定回调函数 . 默认情况parse
yield Request("https://www.baidu.com",callback=self.process_baidu)
def process_baidu(self , response):
print("return : ", response.url, response.meta)
上面你唯一需要注意的就是 name ,全局唯一, scrapy 启动将读取spiders 下的文件. 根据你所指定的 name 来启动爬虫.
只与name字段有关,与类名,文件名都无关
可以自己再次发出请求 , 并指定要处理结果的函数(callback) . 由于twisted机制, 你需要使用yield 而不是 return ;
把这些函数当成生成器来使用.
pipelines: 用于数据存储
初学时只需要写一个函数即可 : process_item .
当然里面还有open_spider 当spider被开启时做点事, from_crawler 可以根据配置文件来创建这个对象等等.具体可查看文档.
一个最简单的 pipeline :
class pipeline1(object):