赞
踩
Scrapy框架中分两类爬虫,Spider类和CrawlSpider类。在Python爬虫之Scrapy框架的使用博文中使用了Spider类来爬取数据。我们是自己在解析完整个页面后获取下一页的url,然后重新发送一个请求。
有时也会有这样的需求,只要满足某个条件的url都进行爬取。此时我们就可以通过CrawlSpider来完成。CrawlSpider继承自spider,只不过是在之前的基础上增加了新的功能。可以定义爬取的url的规则,以后scrapy碰到满足条件的url都进行爬取,而不用手动yield Request。
之前创建爬虫的方式是通过scrapy genspider [爬虫名字] [域名]的方式创建的。如果想要创建CrawlSpider爬虫,那么应该通过以下命令创建:
scrapy genspider -c crawl [爬虫名字] [域名]
使用LinkExtractors可以不用程序员自己提取想要的url,然后发送请求。这些工作都可以交给LinkExtractors,他会在所有爬的页面中找到满足规则的url,实现自动的爬取。以下对LinkExtractors类做一个简单的介绍:
class scrapy.linkextractors.LinkExtractor(
allow = (),
deny = (),
allow_domains = (),
deny_domains = (),
deny_extensions = None,
restrict_xpaths = (),
tags = ('a','area'),
attrs = ('href'),
canonicalize = True,
unique = True,
process_value = None
)
主要参数讲解:
allow:允许的url。所有满足这个正则表达式的url都会被提取。
deny:禁止的url。所有满足这个正则表达式的url都不会被提取。
allow_domains:允许的域名。只有在这个里面指定的域名的url才会被提取。
deny_domains:禁止的域名。所有在这个里面指定的域名的url都不会被提取。
restrict_xpaths:严格的xpath。和allow共同过滤链接。
定义爬虫的规则类。以下对这个类做一个简单的介绍:
class scrapy.spiders.Rule(
link_extractor,
callback = None,
cb_kwargs = None,
follow = None,
process_links = None,
process_request = None
)
主要参数讲解:
link_extractor:一个LinkExtractor对象,用于定义爬取规则。
callback:满足这个规则的url,应该要执行哪个回调函数。因为CrawlSpider使用了parse作为回调函数,因此不要覆盖parse作为回调函数自己的回调函数。
follow:指定根据该规则从response中提取的链接是否需要跟进。
process_links:从link_extractor中获取到链接后会传递给这个函数,用来过滤不需要爬取的链接。
scrapy startproject wxapp
cd wxapp
scrapy genspider -t crawl wxapp_spider wxapp-union.com
from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from wxapp.items import WxappItem class WxappSpiderSpider(CrawlSpider): name = 'wxapp_spider' allowed_domains = ['wxapp-union.com'] start_urls = ['http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1'] rules = ( # 匹配文章列表页分页url,follow=True表示爬取完第一页发现还有符合规则的url接着爬取 Rule(LinkExtractor(allow=r'.+mod=list&catid=2&page=\d'), follow=True), # 匹配文件详情页url Rule(LinkExtractor(allow=r'.+article-.+\.html'), callback = "parse_detail", follow = False), ) def parse_item(self, response): title = response.xpath('//h1/text()').get() authors = response.xpath('//p[@class="authors"]') author = authors.xpath('.//a/text()').get() pub_time = authors.xpath('.//span/text()').get() content = response.xpath('//td[@id="article_content"]//text()').getall() content = ''.join(content).strip() item = WxappItem(title = title, author = author, pub_time = pub_time, content = content) yield item
import scrapy
class WxappItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
author = scrapy.Field()
pub_time = scrapy.Field()
content = scrapy.Field()
from scrapy.exporters import JsonLinesItemExporter
class WxappPipeline:
def __init__(self):
self.fp = open('wx.json', 'wb')
self.exporter = JsonLinesItemExporter(self.fp, ensure_ascii = False, encoding = 'utf-8')
def process_item(self, item, spider):
self.exporter.export_item(item)
return item
def close_spider(self, spider):
self.fp.close()
下面的案例注意使用了两个item类,因为数据不在同一页面获取,而CrawlSpider不可以请求传参,所以将不同页面的数据使用了两item类收集。
1:爬虫文件内容
from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from SunPro.items import SunproItem from SunPro.items import DetailItem class SunSpider(CrawlSpider): name = 'sun' # allowed_domains = ['www.xxx.com'] start_urls = ['http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1'] rules = ( # 获取分页 Rule(LinkExtractor(allow=r'id=1&page=\d+'), callback='parse_item', follow=True), # follow = True 可以将链接提取器继续作用到连接提取器提取到的链接所对应的页面中 Rule(LinkExtractor(allow=r'id=\d+'), callback='parse_detail', follow=False) ) # 如下两个解析方法中不可以实现请求传参,如传递meta;可以将数据保存到两个item中 def parse_item(self, response): # xpath中不能出现tbody li_list = response.xpath('//ul[@class="title-state-ul"]/li') for li in li_list: detail_url = li.xpath('./span[@class="state3"]/a/@href').extract_first() # detail_url = urljoin(response.url, detail_url) title = li.xpath('./span[@class="state3"]/a/text()').extract_first() item = SunproItem(title=title) yield item def parse_detail(self, response): new_id = response.xpath('//div[contains(@class, "focus-date-list")]/span[4]//text()').extract_first() item = DetailItem(new_id=new_id) yield item
2:items文件内容
import scrapy
class SunproItem(scrapy.Item):
title = scrapy.Field()
class DetailItem(scrapy.Item):
new_id = scrapy.Field()
3:pipeline文件内容
class SunproPipeline:
def process_item(self, item, spider):
print(item)
# 判定item的类型
if item.__class__.__name__ == 'DetailItem':
print(item['new_id'])
else:
print(item['title'])
return item
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。