ScrapyでのRulesの理解
: , , , , , 。 + , (link extractor) 。 scrapy , ,
1.
rules = (Rule(SgmlLinkExtractor(allow=('category/20/index_\d+\.html'), restrict_xpaths=("//div[@class='left']"))),
Rule(SgmlLinkExtractor(allow=('a/\d+/\d+\.html'), restrict_xpaths=("//div[@class='left']")), callback='parse_item'),
)
説明:Ruleは、抽出リンクを定義するルールです.上の2つのルールは、リストページの各ページングページと詳細ページに対応しています.キーはrestrict_を介してxpathは、次に登るリンクを抽出するためにページの特定の部分だけを限定する.2.follow用途第一:これは私が豆弁の新刊書を這い出すルールrules=(Rule(LinkExtractor(allow=(r’^https://book.douban.com/subject/[0-9]*/’),),callback=’parse_item',follow=False),)、このルールの下では定義されたstart_を登るだけです.urlsのルールと一致するリンク.followをTrueに変更すると爬虫類がstart_urlsが這い出すページでは、ルールに合ったurlを探して、全局が這い出すまでループします.第二:ruleはcallbackの有無にかかわらず、同じ_parse_response関数は処理しますが、followとcallbackがあるかどうかを判断します.
3.CrawlSpiderの詳細
前に書く
ScrapyベースのSpiderでは、Spiderクラスについて簡単に説明します.Spiderは基本的に多くのことをすることができますが、もしあなたが知乎や簡書全駅に登りたいなら、もっと強い武器が必要かもしれません.CrawlSpiderはSpiderに基づいているが,全局的に這い出すために生まれたと言える.
簡単な説明
CrawlSpiderは、特定のルールを持つWebサイトでよく使われる爬虫類で、Spiderに基づいていくつかの独特な属性を持っています.
rules:ターゲットWebサイトに一致し、干渉を排除するためのRuleオブジェクトの集合です.start_url:開始応答を取得するには、Item、Requestのいずれかを返す必要があります.rulesはRuleオブジェクトの集合なので、ここでもRuleを紹介します.いくつかのパラメータがあります:link_extractor、callback=None、cb_kwargs=None、follow=None、process_links=None、process_request=Noneのlink_extractorは、自分で定義することも、既存のLinkExtractorクラスを使用することもできます.主なパラメータは次のとおりです.
allow:カッコ内の「正規表現」を満たす値が抽出され、空の場合はすべて一致します.deny:この正規表現(または正規表現リスト)と一致しないURLは必ず抽出されません.allow_domains:抽出されるリンクのdomains.deny_domains:リンクが抽出されないdomains.restrict_xpaths:xpath式を使用して、allowと共同でリンクをフィルタします.もう一つ似たようなrestrict_cssの次は公式に提供された例で、ソースコードの観点からよくある問題を解読します.
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
class MySpider(CrawlSpider):
name = 'example.com'
allowed_domains = ['example.com']
start_urls = ['http://www.example.com']
rules = (
# Extract links matching 'category.php' (but not matching 'subsection.php')
# and follow links from them (since no callback means follow=True by default).
Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),
# Extract links matching 'item.php' and parse them with the spider's method parse_item
Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),
)
def parse_item(self, response):
self.logger.info('Hi, this is an item page! %s', response.url)
item = scrapy.Item()
item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()
item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
return item
質問:CrawlSpiderはどのように動作していますか?
CrawlSpiderはSpiderを継承しているので、Spiderのすべての関数があります.まずはstart_requests対start_urlsの各urlは、parseによって受信されるリクエスト(make_requests_from_url)を開始する.Spider内のparseは定義する必要がありますが、CrawlSpiderはparseを定義して応答を解析します(self._parse_response(response,self.parse_start_url,cb_kwargs={},follow=True)parse_responseはcallback,follow,selfの有無に基づいている.follow_linksは異なる操作を実行します
def _parse_response(self, response, callback, cb_kwargs, follow=True):
## callback, callback reques item
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
## follow, _requests_to_follow link。
if follow and self._follow_links:
for request_or_item in self._requests_to_follow(response):
yield request_or_item
そのうち_requests_to_followはまたlink_を取得しますextractor(これは私たちが転送したLinkExtractor)解析ページで得られたlink(link_extractor.extract_links(response))は、urlを加工し(process_links、カスタマイズが必要)、該当するlinkに対してRequestを開始します.使用するprocess_リクエスト(カスタマイズが必要)処理応答.
質問:CrawlSpiderはrulesをどのように取得しますか?
CrawlSpiderクラスはinitメソッドで呼び出されます.compile_rulesメソッドは、rules内の各Ruleを浅いコピーしてコールバック(callback)、処理するリンク(process_links)、および処理する処理要求(process_request)を取得します.
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)
では、Ruleはどのように定義されているのでしょうか.
class Rule(object):
def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
self.link_extractor = link_extractor
self.callback = callback
self.cb_kwargs = cb_kwargs or {}
self.process_links = process_links
self.process_request = process_request
if follow is None:
self.follow = False if callback else True
else:
self.follow = follow
だからLinkExtractorはlink_に伝わりますextractor.
callbackがあるのは指定された関数で処理され、callbackがないのはどの関数で処理されますか?
上の説明から分かるようにparse_responseはcallbackの(応答)responsを処理します.cb_res=callback(response,**cb_kwargs)or()そして_requests_to_followはself.response_downloadedはcallbackに渡され、ページに一致するurlに対してリクエストを開始する.r = Request(url=link.url, callback=self._response_downloaded)
CrawlSpiderでのシミュレーションの登録方法
CrawlSpiderはSpiderと同じようにstart_を使うのでrequestsはAndrewからリクエストを開始しましたLiu大神が参考にしたコードは、上陸をシミュレートする方法を説明しています.
## start_requests,callback
def start_requests(self):
return [Request("http://www.zhihu.com/#signin", meta = {'cookiejar' : 1}, callback = self.post_login)]
def post_login(self, response):
print 'Preparing login'
# _xsrf ,
xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
print xsrf
#FormRequeset.from_response Scrapy , post
# , after_login
return [FormRequest.from_response(response, #"http://www.zhihu.com/login",
meta = {'cookiejar' : response.meta['cookiejar']},
headers = self.headers,
formdata = {
'_xsrf': xsrf,
'email': '[email protected]',
'password': '321324jia'
},
callback = self.after_login,
dont_filter = True
)]
#make_requests_from_url parse, CrawlSpider parse
def after_login(self, response) :
for url in self.start_urls :
yield self.make_requests_from_url(url)
最後にScrapyを貼ります.spiders.CrawlSpiderのソースコードを確認します.
"""
This modules implements the CrawlSpider which is the recommended spider to use
for scraping typical web sites that requires crawling pages.
See documentation in docs/topics/spiders.rst
"""
import copy
import six
from scrapy.http import Request, HtmlResponse
from scrapy.utils.spider import iterate_spider_output
from scrapy.spiders import Spider
def identity(x):
return x
class Rule(object):
def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
self.link_extractor = link_extractor
self.callback = callback
self.cb_kwargs = cb_kwargs or {}
self.process_links = process_links
self.process_request = process_request
if follow is None:
self.follow = False if callback else True
else:
self.follow = follow
class CrawlSpider(Spider):
rules = ()
def __init__(self, *a, **kw):
super(CrawlSpider, self).__init__(*a, **kw)
self._compile_rules()
def parse(self, response):
return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)
def parse_start_url(self, response):
return []
def process_results(self, response, results):
return results
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)
for link in links:
seen.add(link)
r = Request(url=link.url, callback=self._response_downloaded)
r.meta.update(rule=n, link_text=link.text)
yield rule.process_request(r)
def _response_downloaded(self, response):
rule = self._rules[response.meta['rule']]
return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)
def _parse_response(self, response, callback, cb_kwargs, follow=True):
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
if follow and self._follow_links:
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)
内容は簡単な本から来て、いくつか分からないことがあって、後で理解します