情景如下:

一个网页下有一个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选择器的一个坑点的更多相关文章

  1. 爬虫(十一):scrapy中的选择器

    Scrapy提取数据有自己的一套机制,被称作选择器(selectors),通过特定的Xpath或者CSS表达式来选择HTML文件的某个部分Xpath是专门在XML文件中选择节点的语言,也可以用在HTM ...

  2. JavaScript中sort方法的一个坑(leetcode 179. Largest Number)

    在做 Largest Number 这道题之前,我对 sort 方法的用法是非常自信的.我很清楚不传比较因子的排序会根据元素字典序(字符串的UNICODE码位点)来排,如果要根据大小排序,需要传入一个 ...

  3. [Scrapy-6] XPath使用的一个坑

    先上代码: import scrapy from scrapy.selector import Selector class QuoteSpider(scrapy.Spider): name = &q ...

  4. 记自己在mybatis中设置jdbcType的一个坑

    项目是用ssm搭建的.主要是为app数据接口.其中有一个需求就app想要查询一段时间内某个用户的测量信息,所以app给我后端传递了3个参数,分别是appuserId(String),startDate ...

  5. UC浏览器中Ajax请求中传递数据的一个坑

    今天突然收到一个bug,有用户在其浏览器环境中一直无法提交内容,使用的是UC浏览器.当换成Chrome时,内容能够正常提交.鉴于本地没有一直使用Firefox 以及Chrome,于是去下载了一个UC ...

  6. 说说PHP中foreach引用的一个坑

    From: http://blog.csdn.net/yipiankongbai/article/details/45307767 先来看看下面这段代码: <?php $arr = array( ...

  7. 问题记录 | 记录PIL中Image.save的一个坑

    Image.save然后open数值是会变的 我找了一个下午终于找出问题所在,PIL的Image库中把图片resize了之后存在本地然后再读进来,与直接resize后的数值是不一样的. data_va ...

  8. 关于使用layui中的tree的一个坑

    最近几天,因为项目需要,所以自学了下layui,在使用之前就对其比较感兴趣,毕竟封装的东西也不错(个人见解),在接触到layui之后,现在有个需要就是将部门做成tree的样子,开始觉得不怎么难,毕竟都 ...

  9. 记录MYSQL中SQL语句的一个坑.

    MYSQL5.7 假设我们有一个表 : h_member_cards_my  (ID, WXOPEN_ID) 表中有一条记录如下: 理论上第二个SQL应当是可以查询得到一条数据的, 结果却为 Empt ...

随机推荐

  1. Ubuntu系统配置

    0.基本配置 0.1初始设置 (1)开户root账号并重启系统: 打开gedit /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf 添加greeter- ...

  2. 记一次深度系统安装至windows系统盘提示挂载为只读模式问题

    记一次深度系统安装至windows系统盘提示挂载为只读模式问题 来到新公司新电脑自己要安装deepin,安装的时候没考虑双系统直接装至默认win系统盘,导致deepin启动后提示如下: 提示多个挂载分 ...

  3. Vue ElementUI 的使用

    简介: 饿了么公司基于vue开的的vue的Ui组件库        1.Element Ui    基于vue  pc端的UI框架          2. MintUi         基于vue 移 ...

  4. Mock及Mockito使用

    mockito http://www.vogella.com/tutorials/Mockito/article.html 原文地址: http://www.open-open.com/lib/vie ...

  5. DLC 基本定律与规则2

    逻辑函数的相等 布尔代数 9 个定律 三条规则 代入规则

  6. S表示1,L表示2,计算由S和L组成的序列之和为N的组合

    def func(n): def calc_str(s): s = s.strip() if s is not None else "" s = s.upper() result ...

  7. SpringBoot整合StringData JPA

    目录 SpringBoot整合StringData JPA application.yml User.class UserRepository.java UserController SpringBo ...

  8. FPGA笔试必会知识点2—FPGA器件

    FPGA 综合工具并不一定保证能够充分利用芯片结构特点以达到最优目的而且工具本身也不一定非常智能,因为设计本身是复杂多样的且一直在变化,问题总会越来越多,因此在这种情况下,我们必须了解我们的器件结构, ...

  9. 地址栏输入url按回车发生了什么

    浏览器向DNS服务器(先查找缓存)查找输入URL对应的IP地址 DNS服务器返回对应的IP地址 浏览器根据IP地址与目标web服务器在80端口上建立TCP连接 浏览器获取请求页面的html代码 浏览器 ...

  10. sql中的常见报错;

    1.对于某些写的sql懒得判断的: SELECT * FROM sys_part WHERE part_no =(SELECT part_no FROM dbo.sys_part)  --字查询的结果 ...