开头再来波小程序摇一摇:

上一章节,我们讲到了通过Rules来获取下一个待爬页面的URL,那么我们今天就来讲讲具体的怎么爬取一个页面。

因为我们的目的是爬取整个36页的全部美剧列表,但是在36页数据里面,除了第一页,其他35也的网页都是很规律很整齐的,为啥第一页不一样?因为第一页有前三甲的图片,这个我们需要特殊处理一下。所以,今天这节,我们主要来说爬取剩下35页内荣怎么爬。

http://www.ttmeiju.me/index.php/summary/index/p/2.html

0x00_承前

前一篇文章『Scrapy爬虫进阶操作之CrawlSpider(一)』,我们主要讲到了编写 Rule 来提取下一页的URL:

rules = (        Rule(LinkExtractor(restrict_xpaths='//ul[@class="pagination"]//a[@class="next"]'), callback='parse_item', follow=True),    )复制代码

今天,我们就来完善我们这个 Rule 里面的 callback : parse_item() 方法。

0x01_分析

我们要爬取的页面,大概长上图的那个样子。通过观察,看到这里面每项都是很规则的排布,在看网页源码里面,

我们就发现,每一条数据,其实都是一个 tr 标签,这个标签的特点就是 class 里面含有 Scontent 或者 Scontent1 这两个字段。

接着在看 tr 标签内部,每一条美剧信息里面有 7 个内容,即:序号,剧名,分类,状态,更新日期,回归日期和倒计时。我们的目的就是要把这 7 个都摘出来。所以,我们在 items.py 里面创建一个 scrapy.item 类:

class TtmjTvPlayItem(scrapy.Item):    tv_play_name = scrapy.Field()    tv_play_rank = scrapy.Field()    tv_play_category = scrapy.Field()    tv_play_state = scrapy.Field()    tv_play_update_day = scrapy.Field()    tv_play_return_date = scrapy.Field()    tv_play_counting_data = scrapy.Field()    tv_play_url = scrapy.Field()复制代码

这个 scrapy.Item 就是scrapy将爬取结果封装到一个bean中,之后再由用户随便处置这个bean。这些变量就是我们前面说的那 7 个变量。

0x02_爬页面第一步

为了更好的调试,我们先把 Rule 里面的 follow 去掉,或者改为 False。 这个做的目的是我们先用:

http://www.ttmeiju.me/index.php/summary/index/p/2.html复制代码

页面进行调试。将 follow 改为 False,这个时候我们运行下面的代码:

class PlayrankingSpider(CrawlSpider):    name = 'playranking'    allowed_domains = ['www.ttmeiju.me']    # start_urls = ['http://www.ttmeiju.me/']    root_url = "http://www.ttmeiju.me/"    start_urls = ['http://www.ttmeiju.me/index.php/summary/index/p/1.html']    rules = (        # Rule(LinkExtractor(restrict_xpaths='//ul[@class="pagination"]//a[@class="next"]'), callback='parse_item',follow=True),        Rule(LinkExtractor(restrict_xpaths='//ul[@class="pagination"]//a[@class="next"]'), callback='parse_item'),    )    def parse_item(self, response):        print(response.url)复制代码

看到结果显示的是这个样子:

我们看到,去掉follow之后,果然只是爬取两页内容,但是这里 parse_item() 只打印出来第二页的 URL,第一页的URL没有打印出来。这其中的过程在这里简单说一下:

CrawlSpider首先是通过 startUrl 来作为爬虫开始爬取的页面的,所有的 Rules 生效的页面都是在第一个页面以及之后的页面,所以这里,当 Scrapy 向 startUrl 发送第一个请求并得到 response,我们开始调用 Rules 来萃取出来接下来需要爬取的 URL , 所以, parse_item() 这个回调生效的页面就是除了 startUrl 页面的其他页面。

可是我们也要爬取 startUrl 页面里面的东西的啊,别急,我们下一节说这个问题。这一节我们先来搞定除第一个页面的其他页面的爬取。

那么接下来我们就是要从 URL 里面来获取到我们上面 TtmjTvPlayItem 里面各个变量的值了。

0x03_采坑

页面数据很规律,我们还是通过 xPath 来定位元素信息。

每一条美剧的信息,都包裹在 tr 标签下,而且 tr 标签的特点就是 class 里面含有 Scontent 字段。

所以,我们这里可以按照这样的思路来操作:先将所有美剧的 tr 标签爬取出来,成一个 list, 然后再遍历 list 里面的每一个变量,再从中获取出来 各个变量赋值到 TtmjTvPlayItem 里面。

我们使用在上一节提到的 Scrapy Shell 来做 xpath 的定位:

$ scrapy shell http://www.ttmeiju.me/index.php/summary/index/p/2.html$ response.xpath('//tr[contains(@class,"Scontent")]') 复制代码

可以看到结果却是是所有的美剧列表:

然后我们只需要遍历这每一个 tr 标签即可,所以我们的 parse_item() 方法写成这样:

def parse_item(self, response):    tr_list = response.xpath('//tr[contains(@class, "Scontent")]')    for content in tr_list:        name = content.xpath('//td[@align="left"]//a/text()').extract()        print(name)复制代码

这里我们要答应所有的名字,结果发现:

WTF!这尼玛好像把所有的名字都打印出来了,这不是我们想要的结果啊。

这里就是坑!!!

xpath选出来 selectorList 之后,如果想要针对每一个 selector 进行操作,就需要把每一个 selector 先 extract() 出来,再封装成 Selector,之后的操作,就对这个 Selector 操作就可以。

我们将代码改成下面这个样子:

    def parse_item(self, response):        tr_list = response.xpath('//tr[contains(@class, "Scontent")]').extract()        for content in tr_list:            selector = Selector(text=content)            name = selector.xpath('//td[@align="left"]//a/text()').extract()            print(name)复制代码

注意第二行和第四行,第二行调用了extract(),先提取成 string,然后第四行我们在针对每个 string 封装成 selector供下面的使用。这样我们再看打印结果:

看到每个名字都答应出来了。这一步成功了,我们接下来把其他数据搞定就可以了。

0x05_完善数据

针对每一条美剧,名字分布很有规律,就是一个有align属性的 a 标签,其他的内容都是在 td 标签里面。

我们按照上面的思路,把代码改一下,找到所有的td来看一下:

def parse_item(self, response):    tr_list = response.xpath('//tr[contains(@class, "Scontent")]').extract()    for content in tr_list:        selector = Selector(text=content)        td_list = selector.xpath('//td/text()').extract()        tv_name = selector.xpath('//td[@align="left"]//a/text()').extract_first()        print(tv_name)        for td_item in enumerate(td_list):            print(td_item)复制代码

结果很让我们意外:

找到是找到了,结果里面有好多换行符和空格,那么我们只需要简单处理一下:

def parse_item(self, response):    tr_list = response.xpath('//tr[contains(@class, "Scontent")]').extract()    for content in tr_list:        selector = Selector(text=content)        td_list = selector.xpath('//td/text()').extract()        tv_name = selector.xpath('//td[@align="left"]//a/text()').extract_first()        print(tv_name)        for index, td_item in enumerate(td_list):            td_item = td_item.replace('\t', '').strip()            print(td_item)复制代码

这样,我们就可以打印出来正确的结果了:

0x06_找到URL

上面的数据,我们还差一个美剧的URL,这个URL我们分析,是在美剧名字里面:

所以,这里我们用 xpath 定位出来这个标签,然后把数据读取出来就好:

# xpath 取属性用 @+属性名tv_play_url = self.root_url + selector.xpath('//td[@align="left"]//a/@href').extract_first()[1:]复制代码

这里我们发现, xpath 读取 tag 的标签里面某个属性的值,就用 @属性名 就可以。

0x07_整合itmem

我们最后在把 TtmjTvPlayItem 整合到我们的 parse_item() 里面:

def parse_item(self, response):    tr_list = response.xpath('//tr[contains(@class, "Scontent")]').extract()    for content in tr_list:        tv_item = TtmjTvPlayItem()        selector = Selector(text=content)        td_list = selector.xpath('//td/text()').extract()        tv_name = selector.xpath('//td[@align="left"]//a/text()').extract_first()        tv_item['tv_play_name'] = tv_name        for index, td_item in enumerate(td_list):            td_item = td_item.replace('\t', '').strip()            if index == 0:                tv_item['tv_play_rank'] = td_item            elif index == 1:                tv_item['tv_play_category'] = td_item            elif index == 2:                tv_item['tv_play_state'] = td_item            elif index == 3:                tv_item['tv_play_update_day'] = td_item            elif index == 4:                tv_item['tv_play_return_date'] = td_item            elif index == 5:                tv_item['tv_play_counting_data'] = td_item        # xpath 取属性用 @+属性名        tv_item['tv_play_url'] = self.root_url + selector.xpath('//td[@align="left"]//a/@href').extract_first()[1:]        print(tv_item)复制代码

这样,最后的结果就很完美:

读到这里的同学肯定发现了我们还有几个问题没有解决:

  1. 第一页的数据怎么爬取?
  2. 封装好的tv_item改怎么办
  3. 。。。。

这些东西都会在下一讲以及之后的文章里面说,我们最后的目的就是建立一个可以通过json文件动态配置的爬虫。别慌,皮爷一点一点的给大家细细的讲解。

这里说一下哈,所有的爬虫代码,我均已发布到网上了,获取方法很简单,关注公号『皮爷撸码』,回复『代码』即可找到,记住对应的代码编号是『CS001』,代码编号是『CS001』,代码编号是『CS001』。

皮爷撸码』,一个很硬核的公号,如果你能从这里学到知识,皮爷很高兴,很希望你也能够将这份内容分享出去,让更多的人感受到编程的乐趣。

转载于:https://juejin.im/post/5cc029abe51d456e845b422e

Scrapy爬虫进阶操作之CrawlSpider(二)相关推荐

  1. Scrapy爬虫进阶操作之CrawlSpider(三)血崩啊

    开头再来波小程序摇一摇: 上一节,我们说到了爬取普通页面的每一条item怎么搞.相信大家以及对 CrawlSpider 里面的 Rule 有所了解. 接下来,今天我们就做一个完结.写一个通用的Craw ...

  2. python爬虫之逆向破解_Python爬虫进阶之APP逆向(二)

    最近有朋友在做新闻资讯类的 app 爬虫,也许大多数人都会认为,一个新闻资讯 app 不会有什么反爬吧. 恰恰相反,当你想爬一条新闻的时候都有请求参数加密,可见现在反爬的严重性. 分析 国际惯例先抓包 ...

  3. Scrapy 规则化爬虫(1)——CrawlSpider及link_extractor

    Scrapy 规则化爬虫(1)--CrawlSpider及link_extractor 目录 Scrapy 规则化爬虫(1)--CrawlSpider及link_extractor 前言 一.Craw ...

  4. [Python Scrapy爬虫] 二.翻页爬取农产品信息并保存本地

    前面 "Python爬虫之Selenium+Phantomjs+CasperJS" 介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分 ...

  5. 优雅的操作scrapy爬虫的开始和结束

    优雅的操作scrapy爬虫的开始和结束 scrapy 管道中开始和结束信号 scrapy spider中开始和结束信号 scrapy 管道中开始和结束信号 from scrapy import sig ...

  6. python 中主线程结束 子线程还在运行么_Python爬虫进阶(二)爬虫之多任务模块(Ⅰ)...

    今天,咱们来讨论多任务模块了. 一.多任务介绍 二.多线程的创建 一.多任务介绍 多任务,有很多场景中的事情是同时进行的,比如开车的时候,手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的.这些就是多 ...

  7. scrapy框架开发爬虫实战——采集BOSS直聘信息【爬虫进阶】

    项目GitHub https://github.com/liuhf-jlu/scrapy-BOSS- 爬取任务 时间:2019年8月28日 爬取内容:BOSS直聘上的北京市python岗位的招聘信息 ...

  8. 【EduCoder答案】Scrapy爬虫(二)热门网站数据爬取

    简介 答案查询的入口网页版 并不是所有的关卡都有答案,有些只有部分关卡有 不要直接复制答案哦 Scrapy爬虫(二)热门网站数据爬取 >>>查看 第1关:猫眼电影排行TOP100信息 ...

  9. python爬虫之Scrapy框架原理及操作实例详解、股票数据Scrapy爬虫

    爬虫框架 -scrapy.pyspider.crawley等 Scrapy框架 1.scrapy框架介绍 -https://doc.scrapy.org/en/latest/ -http://scra ...

最新文章

  1. postgresql在线备份与恢复(三)
  2. 自定义ActionSheetView
  3. 关于IOS给我的启发
  4. Python、Lua和Ruby比较——脚本语言大P.K.
  5. 《Go语言圣经》学习笔记 第四章 复合数据类型
  6. python位置参数ppt_如何在Python中使用一个或多个相同的位置参数?
  7. 如何不部署Keras / TensorFlow模型
  8. jq 在字符串中,去掉指定的元素
  9. C++学习之路 | PTA乙级—— 1016 部分A+B (15分)(精简)
  10. 关于“服务器提交了协议冲突. Section=ResponseStatusLine问题
  11. Java面向对象封装和继承
  12. SOLIDWORKS Composer生成BOM表属性不显示的解决办法
  13. mysql导出表文件_mysql导出表数据到文件的几种方法
  14. 荣耀笔记本linux版拆机,拆机荣耀 MagicBook 锐龙版,真材实料一眼看到
  15. 【模型选择】从0到1的数据价值实现需要数据分析师做些什么?
  16. 【Week 1】Preferences and Ratings
  17. 读取/保存/写入 图像文件的shape格式
  18. 益银达-分享10个在家就能赚钱的副业推荐,总有一款适合你
  19. 4篇YouTube推荐系统论文, 一起来看看别人家的孩子
  20. 电子签名第三方服务平台,如何保障电子合同安全性的?

热门文章

  1. unity3d IGUI下载
  2. iOS中的UINavigationController
  3. c语言均衡器,关于调音:如何使用动态均衡器?
  4. STM32CubeMX新建Project、下载库
  5. aqr资本二十年精选二十篇_2016年2月:前10名和编辑精选
  6. [笔记]学习HighCharts的使用(不错的web图表插件)
  7. 【安信可LoRa模组专题①】安信可LoRa快速入门指南
  8. 打开unity虚拟轴。
  9. Android之关机/重启/recovery模式(一百一十五)
  10. 横河EJA210E-JHS5J-910DN-EH23B2WE03-B变送器