1 crawlspider是什么
回顾之前的代码中,我们有很大一部分时间在寻找下一页的url地址或者是内容的url地址上面,这个过程能更简单一些么?
思路:
- 从response中提取所有的满足规则的url地址
- 自动的构造自己requests请求,发送给引擎
crawlspider就可以实现上述需求,能够匹配满足条件的url地址,组装成Reuqest对象后自动发送给引擎,同时能够指定callback函数
即:crawlspider爬虫可以按照规则自动获取连接
2 创建crawlspider爬虫并观察爬虫内的默认内容
这次我们将爬取电影天堂中韩剧电影的所有姓名和链接。我们将通过spider和crawlspider分别实现
2.1 spider实现,自己实现翻页操作,并判断是否到达最后一页
import scrapy
from movie_paradise.items import MovieParadiseItem
class CrawlMoviesSpider(scrapy.Spider):
name = 'crawl_movies'
allowed_domains = ['ygdy8.net']
start_urls = ['https://www.ygdy8.net/html/gndy/rihan/']
def parse(self, response):
item = MovieParadiseItem()
movie_list = response.xpath('//table[@class="tbspan"]')
print(len(movie_list))
for movie in movie_list:
item['link'] = movie.xpath('.//a[2]/@href').extract_first()
print(item['link'])
yield item
print('_' * 100)
judge = response.xpath('.//div[@class="x"]//a//text()').extract()
print(judge)
if '下一页' in judge:
i = judge.index('下一页')
print(i)
next = response.xpath('.//div[@class="x"]//a[{}]/@href'.format(i+1)).extract_first()
print(next)
next_url = response.urljoin(next)
print(next_url)
yield scrapy.Request(url=next_url, callback=self.parse)
电影天堂这个网站判断最后一页还是比较麻烦的,如果下一页所在的标签位置不变将会简单很多,代码没问题我就不贴结果了,主要是crawlspiider实现的方式。
2.2 crawlspider实现
创建crawlspider爬虫文件的方式
scrapy genspider -t crawl job 163.com
创建完成后的默认代码如下
下面对各个参数进行讲解:
- Rule常见参数
- LinkExtractor: 链接提取器,可以通过正则或者是xpath来进行url地址的匹配
- callback: 表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理
- follow: 连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,默认True表示会,Flase表示不会
- process_links: 当链接提取器LinkExtractor获取到链接列表的时候调用该参数指定的方法,这个自定义方法可以用来过滤url,且这个方法执行后才会执行callback指定的方法
- 链接提取器LinkExtractor的更多常见参数
- allow: 满足括号中的’re’表达式的url会被提取,如果为空,则全部匹配
- deny: 满足括号中的’re’表达式的url不会被提取,优先级高于allow
- allow_domains: 会被提取的链接的domains(url范围),如:
['hr.tencent.com', 'baidu.com']
- deny_domains: 不会被提取的链接的domains(url范围)
- restrict_xpaths: 使用xpath规则进行匹配,和allow共同过滤url,即xpath满足的范围内的url地址会被提取**,如:
restrict_xpaths='//div[@class="pagenav"]'
我们只需要在rules中编写正则,即可爬取所有符合要求的链接,可以自己打印rules看看他爬取了哪些链接,我已经测试过了,真的是速度快又好
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from movie_paradise.items import MovieParadiseItem
class CrawlMovies2Spider(CrawlSpider):
name = 'crawl_movies2'
allowed_domains = ['ygdy8.net']
start_urls = ['https://www.ygdy8.net/html/gndy/rihan']
# follow 决定是否继续在链接提取器提取的链接对应的响应中继续应用链接提取器,一般持续翻页的链接提取规则需要设置为true
rules = (
Rule(LinkExtractor(allow=r'^.+www.ygdy8.net/html/gndy/rihan.+'), callback='parse_item', follow=True),
)
# print(rules)
def parse_item(self, response):
item = MovieParadiseItem()
movie_list = response.xpath('//table[@class="tbspan"]')
print(len(movie_list))
for movie in movie_list:
item['link'] = movie.xpath('.//a[2]/@href').extract_first()
item['name'] = movie.xpath('.//a[2]/text()').extract_first()
# print(item)
yield item
print('_' * 100)
然后管道中保存
# -*- coding:utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
import json
class MovieParadisePipeline:
def open_spider(self, spider):
self.f = open('电影天堂.txt', 'w')
def process_item(self, item, spider):
item = dict(item)
item = json.dumps(item, ensure_ascii=False) + ',\n'
self.f.write(item)
return item
def close_spider(self, spider):
self.f.close()
保存后的文件
crawlspidr的优势毫无疑问在于链接的爬取,但他对二级请求的处理比价麻烦,如果你要爬取的内容在一个页面上,比如上面的例子,crawlspider再适合不过了。