1.我的目的
- 了解Scrapy的CrawlSpider并使用
2.例子
- 爬取豆瓣读书的所有小说的详情页面
- 每一页的url
/tag/小说?start=7600 、 /tag/小说?start=60
正则匹配这些字符的话写法是 ” /tag/小说?start=[0-9]* “ - 某一部小说的url
https://book.douban.com/subject/1045818/
https://book.douban.com/subject/1046265/
正则匹配这些字符的话写法是 " https://book.douban.com/subject/[0-9]*?/$ "
(这里加$是为了结尾匹配,不匹配结尾的话能匹配到这种url ”https://book.douban.com/subject/1045818/buylinks/“ , 可能是不匹配结尾的话它会把用这个正则能匹配出数据的url都选取下来) - 那么我们可以这样写
class CrawlDoubanSpider(CrawlSpider): name = 'crawl_douban' allowed_domains = ['book.douban.com'] start_urls = ['https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4?start=0&type=T'] rules = ( Rule(LinkExtractor(allow="/tag/小说\?start=[0-9]*"), follow=True), Rule(LinkExtractor(allow="https://book.douban.com/subject/[0-9]*?/$"), follow=False, callback="parse_item"), ) def parse_item(self, response): # your code # response返回的是小说详情页面
- 每一页的url
2.CrawlSpider
- 1.作用
在使用普通Spider类做爬虫时,我们需要自己解析出每一个url然后手动发送对此url的请求 ; 而使用CrawlSpider时,只需要我们设置一定的规则,它会自动按照这种规则去解析url然后发送请求,将结果返回给我们。 - 2.特点及工作机制
- 根据上面的例子理解其运行机制
- 因为CrawlSpider是继承于Spider,所以继承了Spider的方法
- 首先由Spider的start_requests方法根据
start_urls = [‘https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4?start=0&type=T’] 发送请求
- 这次请求的返回CrawlSpider写了函数_parse_response去接收返回的响应
- 因为第一个请求是没有callback的,所以不走进第一个if callback。
- follow默认值是true
- pider._follow_links的值是从settings的CRAWLSPIDER_FOLLOW_LINKS值获取到的(不知道有什么用,先当做一个恒定true吧)
- 所以会进入if follow这个逻辑中:可以看到将我们第一个网页的返回给了_requests_to_follow函数
- _requests_to_follow这个函数的作用是提取我们写的LinkExtractor,根据我们的自定义规则判定传入的网页中是否有满足要求的url,如果有则进行加工并发起Request(这里不附带源码,因为也不像上面的那样容易看懂)
- 因为response中是豆瓣小说第一页的内容,根据我定义的规则,是能找到第一页所有小说的url以及下几页的url的,匹配之后他们被重新加工为Request再次请求豆瓣服务器
- 第一种:eg.xxx小说具体内容 Rule(LinkExtractor(allow=“https://book.douban.com/subject/[0-9]*?/$”), follow=False, callback=“parse_item”)
- 依然走进函数_parse_response,因为有callback,所以走进if callback的逻辑—将response返回给parse_item函数解析然后获取得到的Request或item
- 这里我们手动设置了follow为False,所以_parse_response的第二个if逻辑就不会进去了
- 第二种:eg.豆瓣小说第二页的内容 Rule(LinkExtractor(allow="/tag/小说?start=[0-9]*"), follow=True)
- 没有设置callback,所以是不走进_parse_response的第一个if
- follow为True,走进第二个if,做的事与第一次请求一样,只是因为第二页可提取的后面几页的url相比较第一页多(eg.第一页只能获取234,第二页就能获取345),所以我们需要将这里的follow设为True,不然就无法提取所有页中的小说了。
- 第一种:eg.xxx小说具体内容 Rule(LinkExtractor(allow=“https://book.douban.com/subject/[0-9]*?/$”), follow=False, callback=“parse_item”)
- 后面的请求以此类推就可以了。
来源:https://blog.csdn.net/shwwns/article/details/101243032