Scrapy 是用纯 Python 实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,
用途非常广泛。
框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页
内容以及各种图片,非常之方便。
Scrapy 使用了 Twisted['twɪstɪd](其主要对手是 Tornado)异步网络框架来处理网络通讯,
可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵
活的完成各种需求。
注意这个是scrapy重中之重的原理图
- Scrapy Engine(引擎): 负责 Spider、ItemPipeline、Downloader、Scheduler 中间的通讯,信号、数据传递等。
- Scheduler(调度器): 它负责接受引擎发送过来的 Request 请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
- Downloader(下载器):负责下载 Scrapy Engine(引擎)发送的所有 Requests 请求,并将其获取到的 Responses 交还给 Scrapy Engine(引擎),由引擎交给 Spider 来处理。
- Spider(爬虫):它负责处理所有 Responses,从中分析提取数据,获取 Item 字段需要的数据,并将需要跟进的 URL 提交给引擎,再次进入 Scheduler(调度器)。
- Item Pipeline(管道):它负责处理 Spider 中获取到的 Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
- Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
- Spider Middlewares(Spider 中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider 中间通信的功能组件(比如进入 Spider 的 Responses;和从 Spider 出去的 Requests)
Scrapy 的运作流程
代码写好,程序开始运行... 引擎:Hi!Spider, 你要处理哪一个网站?
Spider:老大要我处理 xxxx.com。
引擎:你把第一个需要处理的 URL 给我吧。
Spider:给你,第一个 URL 是 xxxxxxx.com。
引擎:Hi!调度器,我这有 request 请求你帮我排序入队一下。
调度器:好的,正在处理你等一下。
引擎:Hi!调度器,把你处理好的 request 请求给我。
调度器:给你,这是我处理好的 request
引擎:Hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个 request 请求
下载器:好的!给你,这是下载好的东西。(如果失败:sorry,这个 request 下载失败
了。然后引擎告诉调度器,这个 request 下载失败了,你记录一下,我们待会儿再下载)
引擎:Hi!Spider,这是下载好的东西,并且已经按照老大的下载中间件处理过了,你
自己处理一下(注意!这儿 responses 默认是交给 def parse()这个函数处理的)
Spider:(处理完毕数据之后对于需要跟进的 URL),Hi!引擎,我这里有两个结果,
这个是我需要跟进的 URL,还有这个是我获取到的 Item 数据。
引擎:Hi !管道 我这儿有个 item 你帮我处理一下!调度器!这是需要跟进 URL 你帮
我处理下。然后从第四步开始循环,直到获取完老大需要全部信息。
管道``调度器:好的,现在就做!
注意!只有当调度器中不存在任何 request 了,整个程序才会停止,(也就是说,对于
下载失败的 URL,Scrapy 也会重新下载。)
总结:拿实例来解释理解起来确实费劲
这个时候有了url,spiders将url交给了scrapyengine,然后scrapyengine让scheduler去处理request请求,将结果给引擎,接着scrapyengine让downloader去下载这个request请求,将结果给引擎,这个中间件downloadermiddlewares说白了就是写我们的反反爬虫策略的,然后这个时候处理的已经处理完了,拿到了对应的response,我们的parse函数是专门来接收response并且开始抓取具体的业务,在这里会有分支,就是深度爬取,比如说当前页的详情页,那么详情页需要再写一个函数在self(这里的self指的是需要深度爬取的函数)函数里进行callback,也就是上图的yield部分,这个时候会在接下来的函数接着重复之前的操作,以为每深进一个url就要重复上述操作即从引擎开始到这里的步骤,直到没有下一个链接在最后一个没有链接的函数里进行yield item。另一个就是没有深度爬取直接返回item,直接返回item之后引擎会把item给管道,管道就是我们与数据库打交道的,写好连接数据库的业务逻辑,开始入库。
这是自己写的中间件注意要继承object然后就是自己定义的这些函数需要的参数不要落下,
class GuaZi(object):
#设置cookie
def process_request(self,request,spider):
request.cookies = {
"uuid": "d3bdd02f-e0d2-4a63-d0fd-4100a4c3d963",
"antipas":"s41587E6229ZE29Y363371M1I82",
"cityDomain":"bj",
"clueSourceCode":"10103000312%2300",
"user_city_id":"12",
"preTime":"%7B%22last%22%3A1562651840%2C%22this%22%3A1562651840%2C%22pre%22%3A1562651840%7D",
"ganji_uuid":"8536057584891394286262",
"sessionid":"be2b22ee-cca9-4589-848c-01b5977eed31",
"lg":"1",
"cainfo":"%7B%22ca_s%22%3A%22pz_baidu%22%2C%22ca_n%22%3A%"
"22tbmkbturl%22%2C%22ca_medium%22%3A%22-%22%2C%22ca"
"_term%22%3A%22-%22%2C%22ca_content%22%3A%22%22%2C%22ca"
"_campaign%22%3A%22%22%2C%22ca_kw%22%3A%22-%22%2C%22"
"keyword%22%3A%22-%22%2C%22ca_keywordid%22%3A%22-%22%2C%22"
"scode%22%3A%2210103000312%22%2C%22ca_transid%22%3A%22%22%2C%"
"22platform%22%3A%221%22%2C%22version%22%3A1%2C%22ca_i%22%3A%22"
"-%22%2C%22ca_b%22%3A%22-%22%2C%22ca_a%22%3A%22-%22%2C%22display"
"_finance_flag%22%3A%22-%22%2C%22client_ab%22%3A%22-%22%2C%22guid"
"%22%3A%22d3bdd02f-e0d2-4a63-d0fd-4100a4c3d963%22%2C%22sessionid%22"
"%3A%22be2b22ee-cca9-4589-848c-01b5977eed31%22%7D"
}
request.headers['User-Agent'] = 'Mozilla / 5.0(Windows NT 6.1;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 73.0.3683.86Safari / 537.36'
#设置代理
class ProxyMiddleware(object):
def process_request(self,request,spider):
if request.url.startswith("http://"):
request.meta['proxy']="http://"+'202.120.38.131:80' # http代理
elif request.url.startswith("https://"):
request.meta['proxy']="https://"+'202.120.38.131:80' #https代理
注意:要在setting中打开
items目标字段
管道