在抓取工作时,难免会遇到要爬取的站点量非常大的时候,如某些媒体网站的新闻详情页信息,如果单个抓取,就会出现很多重复的代码,造成不必要的麻烦。
因此,我们可以把不同url里的相同抓取规则提取出来,当我们新增一个类似爬虫时就可以直接拿来用了。
CrawlScrapy
官方文档:
http://scrapy.readthedocs.io/en/latest/topics/spiders.html#crawlspider
CrawlSpider是Scrapy提供的一个通用Spider。在Spider里,我们可以指定一些爬取规则来实现页面的提取,这些爬取规则由一个专门的数据结构Rule表示。Rule里包含提取和跟进页面的配置,Spider会根据Rule来确定当前页面中的哪些链接需要继续爬取、哪些页面的爬取结果需要用哪个方法解析等。
Rule:
class scrapy.contrib.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)复制代码
其中主要的就是第一个参数
class scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=False, unique=True, process_value=None, strip=True)
allow是一个正则表达式或正则表达式列表,它定义了从当前页面提取出的链接哪些是符合要求的,只有符合要求的链接才会被跟进。deny则相反。
allow_domains定义了符合要求的域名,只有此域名的链接才会被跟进生成新的Request,它相当于域名白名单。deny_domains则相反,
相当于域名黑名单。restrict_xpaths定义了从当前页面中XPath匹配的区域提取链接,其值是XPath表达式或XPath表达式列表。
restrict_css定义了从当前页面中CSS选择器匹配的区域提取链接,其值是CSS选择器或CSS选择器列表。
实例
爬取内容为中华网资讯:
http://tech.china.com/articles/
通过分析源码可知,在每一个分栏下的每一条详情页都是相通的爬取规则,因此先把详情页规则抽取出来编写为一个rule:
Rule(LinkExtractor(allow='article\/.*\.html', restrict_xpaths='//div[@id="rank-defList"]//div['
'@class="item_con"]'), callback='parse_item')
最后在把下一页的规则抽取出来:
Rule(LinkExtractor(restrict_xpaths='//div[@class="pages"]//a[contains(., "下一页")]'))
重要的两步就写完了,其他就可以顺着写了
items:
import scrapy
class UniversalscrapyproItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
url = scrapy.Field()
text = scrapy.Field()
datetime = scrapy.Field()
source = scrapy.Field()
spider:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from universalscrapyPro.items import UniversalscrapyproItem
class UniversaltestSpider(CrawlSpider):
name = 'universalTest'
# allowed_domains = ['tech.china.com']
start_urls = ['http://tech.china.com/articles/']
rules = (
Rule(LinkExtractor(allow='article\/.*\.html', restrict_xpaths='//div[@id="rank-defList"]//div['
'@class="item_con"]'), callback='parse_item'),
Rule(LinkExtractor(restrict_xpaths='//div[@class="pages"]//a[contains(., "下一页")]'))
)
def parse_item(self, response):
item = UniversalscrapyproItem()
#item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
#item['name'] = response.xpath('//div[@id="name"]').get()
#item['description'] = response.xpath('//div[@id="description"]').get()
item['title'] = response.xpath('//*[@id="chan_newsTitle"]/text()').extract_first()
item['url'] = response.url
item['text'] = "".join(response.xpath('//*[@id="chan_newsDetail"]//text()').extract()).strip()
item['datetime'] = response.xpath('//*[@id="js-article-title"]/div[2]/span[1]/text()').re_first('(\d+-\d+-\d+\s'
'\d+:\d+:\d+)')
item['source'] = response.xpath('//*[@id="js-article-title"]/div[2]/span[2]/text()').extract_first()
yield item