使用scrapy中xpath选择器的一个坑点
情景如下:
一个网页下有一个ul,这个ur下有125个li标签,每个li标签下有我们想要的 url 字段(每个 url 是唯一的)和 price 字段,我们现在要访问每个li下的url并在生成的请求中携带该请求的price字段
毫无疑问,这里是要用到scrapy项目内meta传参的,那么我们思路可能是这样:
1)start_requests访问初始网页
2)定义一个 parse 方法,通过xpath选择器获取所有的li标签,遍历每个 li 标签,获取 url 和 price 字段,生成目标地址为 url 的 scrapy.Request对 象,将 price 打包到 Request 对象的 meta 中,分别yield新地址为 url 的 scrapy.Request 对象
3)对新的 response 进行处理
现在问题出在第2)步骤中:
我们可能发现遍历 li 标签获取的 url 和 price 对象都是一样的,如
In [20]: url_item = response.xpath('//ul[contains(@class, "house-list")]/li')
In [21]: for item in url_item:
...: url = item.xpath('//h2[@class="title"]/a/@href').extract_first()
...: print(url)
...:
https://bj.58.com/ershoufang/37822311633030x.shtml
https://bj.58.com/ershoufang/37822311633030x.shtml
https://bj.58.com/ershoufang/37822311633030x.shtml
......省略122个相同url
可以猜想scrapy中scrapy.selector.unified.SelectorList对象在进行遍历时对子元素操作时,事实上并不是对子元素的操作,而是仍然在对这个SelectorList对象进行操作
In [24]: for item in url_item:
...: url = url_item.xpath('//h2[@class="title"]/a/@href').extract_first()
...: print(url)
...:
https://bj.58.com/ershoufang/37822311633030x.shtml
https://bj.58.com/ershoufang/37822311633030x.shtml
https://bj.58.com/ershoufang/37822311633030x.shtml
......省略122个相同url
以上两种结果完全一致,为了证明我的猜想,我这次在遍历时不用extract_first(),而使用extract(),结果如下:
In [34]: for item in url_item:
...: urls = url_item[2].xpath('//h2[@class="title"]/a/@href').extract()
...: print(urls)
...:
['https://bj.58.com/ershoufang/37822311633030x.shtml', 'https://bj.58.com/ershoufang/37834554715403x.shtml', 'https://bj.58.com/ershoufang/37769196098828x.shtml',
.....省略121个不同url
'https://bj.58.com/ershoufang/37398992001320x.shtml']
......省略和上面相同的123个列表
['https://bj.58.com/ershoufang/37822311633030x.shtml', 'https://bj.58.com/ershoufang/37834554715403x.shtml', 'https://bj.58.com/ershoufang/37769196098828x.shtml',
.....
'https://bj.58.com/ershoufang/37398992001320x.shtml']
分析:遍历的每个item里面只有自己唯一的url,即使extract(),打印的也应该是含自己唯一的url的列表,并且每个item打印的url列表各不相同,
但实际每个item打印的列表包含了所有的url,且每个item打印的url列表完全一致,并且每个item中这个一致的url列表与item的父元素url_item的url列表一致:
In [37]: response.xpath('//ul[contains(@class, "house-list")]/li//h2[@class="title"]/a/@href').extract()
Out[37]:
['https://bj.58.com/ershoufang/37822311633030x.shtml',
'https://bj.58.com/ershoufang/37834554715403x.shtml',
'https://bj.58.com/ershoufang/37769196098828x.shtml',
......省略121个不同url
'https://bj.58.com/ershoufang/37398992001320x.shtml']
结果证实了我的猜想,这也就是我说的scapy中xpath选择器的坑,那么还是面对我最开始提出的情景,该如何解决呢?
在这里提供两种思路:
1)不要使用scrapy中xpath选择器的链式解析,在拿到scrapy.selector.unified.SelectorList对象后,不要通过遍历直接链式解析,直接提取出html文本列表,并对这个列表进行遍历,对每个子元素再生成 scrapy.selector.unified.Selector 对象,然后通过 xpath 提取数据,如下
In [52]: url_item = response.xpath('//ul[contains(@class, "house-list")]/li')
In [53]: items = url_item.extract()
In [55]: for item in items:
...: sele_obj = scrapy.Selector(text=item)
...: url = sele_obj.xpath('//h2[@class="title"]/a/@href').extract_first()
...: print(url)
...:
https://bj.58.com/ershoufang/37822311633030x.shtml
https://bj.58.com/ershoufang/37834554715403x.shtml
https://bj.58.com/ershoufang/37769196098828x.shtml
......省略121个不同url
'https://bj.58.com/ershoufang/37398992001320x.shtml'
方法一
成功拿到每个 li 下的url
2)使用scrapy中xpath选择器的链式解析,在拿到scrapy.selector.unified.SelectorList对象后,开始改用 css 选择器解析:
In [60]: url_item = response.css('ul[class *= "house-list"]>li')
In [61]: for item in url_item:
...: url = item.css('h2.title>a::attr(href)').extract_first()
...: print(url)
...:
https://bj.58.com/ershoufang/37822311633030x.shtml
https://bj.58.com/ershoufang/37834554715403x.shtml
https://bj.58.com/ershoufang/37769196098828x.shtml
......省略121个不同url
https://bj.58.com/ershoufang/37398992001320x.shtml
方法二
使用scrapy中xpath选择器的一个坑点的更多相关文章
- 爬虫(十一):scrapy中的选择器
Scrapy提取数据有自己的一套机制,被称作选择器(selectors),通过特定的Xpath或者CSS表达式来选择HTML文件的某个部分Xpath是专门在XML文件中选择节点的语言,也可以用在HTM ...
- JavaScript中sort方法的一个坑(leetcode 179. Largest Number)
在做 Largest Number 这道题之前,我对 sort 方法的用法是非常自信的.我很清楚不传比较因子的排序会根据元素字典序(字符串的UNICODE码位点)来排,如果要根据大小排序,需要传入一个 ...
- [Scrapy-6] XPath使用的一个坑
先上代码: import scrapy from scrapy.selector import Selector class QuoteSpider(scrapy.Spider): name = &q ...
- 记自己在mybatis中设置jdbcType的一个坑
项目是用ssm搭建的.主要是为app数据接口.其中有一个需求就app想要查询一段时间内某个用户的测量信息,所以app给我后端传递了3个参数,分别是appuserId(String),startDate ...
- UC浏览器中Ajax请求中传递数据的一个坑
今天突然收到一个bug,有用户在其浏览器环境中一直无法提交内容,使用的是UC浏览器.当换成Chrome时,内容能够正常提交.鉴于本地没有一直使用Firefox 以及Chrome,于是去下载了一个UC ...
- 说说PHP中foreach引用的一个坑
From: http://blog.csdn.net/yipiankongbai/article/details/45307767 先来看看下面这段代码: <?php $arr = array( ...
- 问题记录 | 记录PIL中Image.save的一个坑
Image.save然后open数值是会变的 我找了一个下午终于找出问题所在,PIL的Image库中把图片resize了之后存在本地然后再读进来,与直接resize后的数值是不一样的. data_va ...
- 关于使用layui中的tree的一个坑
最近几天,因为项目需要,所以自学了下layui,在使用之前就对其比较感兴趣,毕竟封装的东西也不错(个人见解),在接触到layui之后,现在有个需要就是将部门做成tree的样子,开始觉得不怎么难,毕竟都 ...
- 记录MYSQL中SQL语句的一个坑.
MYSQL5.7 假设我们有一个表 : h_member_cards_my (ID, WXOPEN_ID) 表中有一条记录如下: 理论上第二个SQL应当是可以查询得到一条数据的, 结果却为 Empt ...
随机推荐
- python之路——20
学习内容 1.序列化——数据类型转向字符串数据类型 反序列化——字符串转向数据类型2.序列化模块 json模块 通用序列化格式 弊端:只有少部分数据类型可通过json转化 pickle模块 所有的py ...
- source insight 中文乱码解决方法
options->preferences -> Files-> default encoding: 选择 GB2312 CP:936
- Java BASE58 以及 md5,sha256,sha1
package cn.ubibi.wsblog.utils; import java.io.UnsupportedEncodingException; import java.math.BigInte ...
- spring boot 使用 EnvironmentAware 加载配置文件
@Configuration public class PropertiesUtils implements EnvironmentAware { private int redisExpireTim ...
- docker 删除指令
杀死所有正在运行的容器 docker kill $(docker ps -a -q) 删除所有已经停止的容器 docker rm $(docker ps -a -q) 删除所有未打 dangling ...
- 自学大数据(hadoop)第一天
熟悉linux系统 1.安装linux系统-ubuntu 官网链接:https://www.ubuntu.com/download 下载ubuntu desktop 即可,拖拽到VMvare里即可安装 ...
- Java异常处理——如何跟踪异常的传播路径?
当程序中出现异常时,JVM会依据方法调用顺序依次查找有关的错误处理程序. 可使用printStackTrace 和 getMessage方法了解异常发生的情况: printStackTrace:打印方 ...
- 关于如何在电脑上安装adb来操作手机(Android)的方法及步骤
1.需要真实的安卓手机: 2.安卓手机需要开启USB调试模式,允许电脑进行调试(各个手机的开启方式可能不同,不知道的自行百度): 3.电脑需要安装ADB驱动,这里提供一个下载地址:https://ad ...
- Django models中的null和blank的区别
blank在数据库上存储的是一个空字符串 如需设置字段可以为空:blank=True,默认为blank=False(字段必须填写); null在数据库上表现为NULL,而不是一个空字符串 如需设置字段 ...
- ubuntu安装python版本的opencv
安装命令: pip install opencv-python