CrawlSpider:Spider的子类
1.Spider的用法:
name
定义spider名字的字符串(string)。
allow_domains
允许爬取的域名,是可选配置,不在此域名范围的链接,不会被跟进爬取。
start_urls
URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面
的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。
start_requests()
此方法用于生成初始请求,它必须必须返回一个可迭代对象。此方法会默认使用start_urls里面的URL来构建Request,
而且Request是以GET方式进行请求。如果我们想在启动时,想以POST的请求方式访问某个网站,可以直接重写这个方法。
parse()
当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法。
parse 负责处理response并返回处理的数据以及(/或)跟进的URL。 Spider 对其他的Request的回调函数也有相同的要求。
该方法及其他的Request回调函数必须返回一个包含 Request、dict 或 Item 的可迭代的对象。
close()
当spider关闭时,该函数被调用。有一个参数reason,表示当前参数中断的原因。
2.CrawlSpider源码
class CrawlSpider(Spider):
rules = ()
def __init__(self, *a, **kw):
super(CrawlSpider, self).__init__(*a, **kw)
self._compile_rules()
#1、首先调用parse()方法来处理start_urls中返回的response对象。
#2、parse()将这些response对象传递给了_parse_response()函数处理,并设置回调函数为parse_start_url()。
#3、设置了跟进标志位True,即follow=True。
#4、返回response。
def parse(self, response):
return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)
#处理start_url中返回的response,需要重写。
def parse_start_url(self, response):
return []
def process_results(self, response, results):
return results
def _build_request(self, rule, link):
#构造Request对象,并将Rule规则中定义的回调函数作为这个Request对象的回调函数。这个‘_build_request’函数在下面调用。
r = Request(url=link.url, callback=self._response_downloaded)
r.meta.update(rule=rule, link_text=link.text)
return r
#从response中抽取符合任一用户定义'规则'的链接,并构造成Resquest对象返回。
def _requests_to_follow(self, response):
if not isinstance(response, HtmlResponse):
return
seen = set()
#抽取所有链接,只要通过任意一个'规则',即表示合法。
for n, rule in enumerate(self._rules):
links = [lnk for lnk in rule.link_extractor.extract_links(response)
if lnk not in seen]
if links and rule.process_links:
links = rule.process_links(links)
#将链接加入seen集合,为每个链接生成Request对象,并设置回调函数为_repsonse_downloaded()。
for link in links:
seen.add(link)
#构造Request对象,并将Rule规则中定义的回调函数作为这个Request对象的回调函数。这个‘_build_request’函数在上面定义。
r = self._build_request(n, link)
#对每个Request调用process_request()函数。该函数默认为indentify,即不做任何处理,直接返回该Request。
yield rule.process_request(r)
#处理通过rule提取出的连接,并返回item以及request。
def _response_downloaded(self, response):
rule = self._rules[response.meta['rule']]
return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)
#解析response对象,使用callback解析处理他,并返回request或Item对象。
def _parse_response(self, response, callback, cb_kwargs, follow=True):
#1、首先判断是否设置了回调函数。(该回调函数可能是rule中的解析函数,也可能是 parse_start_url函数)
#2、如果设置了回调函数(parse_start_url()),那么首先用parse_start_url()处理response对象,
#3、然后再交给process_results处理。返回cb_res的一个列表。
if callback:
cb_res = callback(response, **cb_kwargs) or ()
cb_res = self.process_results(response, cb_res)
for requests_or_item in iterate_spider_output(cb_res):
yield requests_or_item
#如果需要跟进,那么使用定义的Rule规则提取并返回这些Request对象。
if follow and self._follow_links:
#返回每个Request对象。
for request_or_item in self._requests_to_follow(response):
yield request_or_item
def _compile_rules(self):
def get_method(method):
if callable(method):
return method
elif isinstance(method, six.string_types):
return getattr(self, method, None)
self._rules = [copy.copy(r) for r in self.rules]
for rule in self._rules:
rule.callback = get_method(rule.callback)
rule.process_links = get_method(rule.process_links)
rule.process_request = get_method(rule.process_request)
@classmethod
def from_crawler(cls, crawler, *args, **kwargs):
spider = super(CrawlSpider, cls).from_crawler(crawler, *args, **kwargs)
spider._follow_links = crawler.settings.getbool(
'CRAWLSPIDER_FOLLOW_LINKS', True)
return spider
def set_crawler(self, crawler):
super(CrawlSpider, self).set_crawler(crawler)
self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)
举例1:首次get请求
from scrapy.spider import CrawlSpider
import scrapy
from bs4 import BeautifulSoup
from pss.pss.items import PssItem
class MySpider(CrawlSpider):
name = 'myspider'
start_urls=['http://lol.qq.com/web201310/info-heros.shtml#Navi']
def parse(self, response):
print(response.body.decode('utf-8'))
soup = BeautifulSoup(response.body.decode('utf-8'), 'html.parser')
tags = soup.select('#jSearchHeroDiv > li > a > img')
for tag in tags:
yield scrapy.Request(url=tag['src'],callback=self.download,meta={'name':tag['src'].split("/")[-1]})
def download(self,response):
item=PssItem()
item['data']=response.body
item['name']=response.meta['name']
yield item
举例2:首次post请求
from scrapy.spider import CrawlSpider
import scrapy
import json
class LaGou(CrawlSpider):
name = 'myspider'
def start_requests(self):
yield scrapy.FormRequest(
url='https://www.lagou.com/jobs/positionAjax.json?city=%E5%B9%BF%E5%B7%9E&needAddtionalResult=false',
#formdata中的key和value必须为字符串
formdata={
'first': 'true',#这里不能给bool类型的True
'pn': '1',#这里不能给int类型的1
'kd': 'python'
},
callback=self.parse
)
def parse(self, response):
datas=json.loads(response.body.decode())['content']['positionResult']['result']
for data in datas:
print(data['companyFullName'] + str(data['positionId']))