情景如下:

一个网页下有一个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. Linux期中架构

    1    在构建完模板后  开启虚拟机后 需要再重启一次  以解决网卡不能看见的问题 ########################################add begin 2018-05 ...

  2. [UE4]Spline Mesh Actor

    作用: 1.按照Spline设置的轨迹,进行显示网格物体. 曲线模型 一.赋值Static Mesh,任意的Static Mesh都可以. 二.调整方向 三.Spline Mesh Actor有2个端 ...

  3. C/C++中指针和java的引用区别

    C++指针  要区分指针变量和指针变量所指对象. 指针变量先是一个变量,它有自己的地址和存储的内容,所以要想清楚是改变指针变量的值(即地址),还是改变指针变量所指对象的值. #include < ...

  4. 在做MVC和WebApi写返回数据时,可以这样定义

    public class Messages { /// <summary> /// 返回包含是否成功以及消息字符结果 /// </summary> /// <param ...

  5. stm32 uart 中断 蜜汁bug

    在项目中,使用stm32f103,配置uart1接收RXNE中断,使用DMA来进行UART1的发送. 初始化代码如下: void uart_init(u32 bound) { GPIO_InitTyp ...

  6. Comparator与Comparable,自定义排序和类比较器,TreeSet对象排序

    /** * 学生类 * @author Administrator * */ public class Student { private String sno ; private String sn ...

  7. 判断单向连通图(拓扑排序+tarjan缩点)

    题意: 给你一个有向图,如果对于图中的任意一对点u和v都有一条从u到v的路或从v到u的路,那么就输出’Yes’,否则输出’No’. 理解:当出现两个及以上入度为0的点(有一个就可能是别人到它,有两个的 ...

  8. sublimit 编辑器 设置默认的编码

    1.首选项>>设置 - 用户 2.加上:"default_encoding": "UTF-8"

  9. LeetCode100.相同的树

    给定两个二叉树,编写一个函数来检验它们是否相同. 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的. 示例 1: 输入: 1 1 / \ / \ 2 3 2 3 [1,2,3], [1 ...

  10. Linux部署笔记分享

    # Linux部署 ## 安装lrzsz1. 安装lrzsz: yum -y install lrzsz2. 进入tmp目录3. rz 上传安装文件 jdk-8u65-linux-x64.tar.gz ...