博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Scrapy】 selector 学习记录二(re,set)
阅读量:7072 次
发布时间:2019-06-28

本文共 5365 字,大约阅读时间需要 17 分钟。

hot3.png

正则表达式(re)

xpath 中的 starts-with() 或者 contians() 无效时 ,可以采用 retest() 函数。

例如:

>>> from scrapy import Selector>>> doc = """... 
... """>>> sel = Selector(text=doc, type="html")>>> sel.xpath('//li//@href').extract()[u'link1.html', u'link2.html', u'link3.html', u'link4.html', u'link5.html']>>> sel.xpath('//li[re:test(@class, "item-\d$")]//@href').extract()[u'link1.html', u'link2.html', u'link4.html', u'link5.html']>>>

C语言库 libxslt 不原生支持EXSLT正则表达式,因此** lxml 在实现时使用了Python re** 模块的钩子。 因此,在XPath表达式中使用regexp函数可能会牺牲少量的性能。

集合操作 (Set)

集合操作可以方便地用于在提取文字元素前从文档树中去除一些部分。 例如使用itemscopes组和对应的itemprops来提取微数据(microdata)(来自):

>>> doc = """... 
...
Kenmore White 17" Microwave...
Kenmore 17" Microwave...
... Rated
3.5/5... based on
11 customer reviews...
......
...
$55.00...
In stock...
...... Product description:...
0.7 cubic feet countertop microwave.... Has six preset cooking categories and convenience features like... Add-A-Minute and Child Lock....... Customer reviews:......
...
Not a happy camper -... by
,...
April 1, 2011...
...
...
1/...
5stars...
...
The lamp burned out and now I have to replace... it. ...
......
...
Value purchase -... by
,...
March 25, 2011...
...
...
4/...
5stars...
...
Great microwave for the price. It is small and... fits in my apartment....
... ......
... """
>>> sel = Selector(text=doc, type="html")>>> for scope in sel.xpath('//div[@itemscope]'):  #获取每一个 div 域,共有七个 div 域...     print "current scope:", scope.xpath('@itemtype').extract() # 提取 div 中的 itemtype 元素...     props = scope.xpath('''...                 set:difference(./descendant::*/@itemprop,...                                .//*[@itemscope]/*/@itemprop)''') # 提取相对 div 域中下一层 标签 中的 itemprop 元素...     print "    properties:", props.extract()...     printcurrent scope: [u'http://schema.org/Product']    properties: [u'name', u'aggregateRating', u'offers', u'description', u'review', u'review']current scope: [u'http://schema.org/AggregateRating']    properties: [u'ratingValue', u'reviewCount']current scope: [u'http://schema.org/Offer']    properties: [u'price', u'availability']current scope: [u'http://schema.org/Review']    properties: [u'name', u'author', u'datePublished', u'reviewRating', u'description']current scope: [u'http://schema.org/Rating']    properties: [u'worstRating', u'ratingValue', u'bestRating']current scope: [u'http://schema.org/Review']    properties: [u'name', u'author', u'datePublished', u'reviewRating', u'description']current scope: [u'http://schema.org/Rating']    properties: [u'worstRating', u'ratingValue', u'bestRating']>>>

在这里,我们首先在 itemscope 元素上迭代,对于其中的每一个元素,我们寻找所有的 itemprops 元素,并排除那些本身在另一个 itemscope 内的元素。

Some XPath tips

1. 谨慎的使用text nodes

当你想要使用文本内容作为XPath函数的参数时,避免使用 .//text() ,采用 . 来替代 这是因为.//text()会产生一个text元素的集合——一个节点集合。当一个node-set被转换成一个string(例如,当它被当做参数传递给contains()或者start-with()函数的时候),它只返回第一个元素。

示例如下:

>>> from scrapy import Selector>>> sel = Selector(text='Click here to go to the Next Page')

把一个node-set转化成string:

>>> sel.xpath('//a//text()').extract() # 查看一下node-set[u'Click here to go to the ', u'Next Page']>>> sel.xpath("string(//a[1]//text())").extract() #转换成string[u'Click here to go to the ']

节点被转化成了string,但是,它本身以及子节点都放在了一起。

>>> sel.xpath("//a[1]").extract() # select the first node[u'Click here to go to the Next Page']>>> sel.xpath("string(//a[1])").extract() # convert it to string[u'Click here to go to the Next Page']

因此,使用 ** .//text()node-set ** 不会得到任何结果:

>>> sel.xpath("//a[contains(.//text(), 'Next Page')]").extract()[]

但是,用 . 会奏效:

>>> sel.xpath("//a[contains(., 'Next Page')]").extract()[u'Click here to go to the Next Page']

2. 注意 //node[1] 和(//node)[1]的区别

  • //node[1] 选择它们的父节点的第一个子节点(occurring first under their respective parents)
  • (//node)[1] 选择文档中的所有node,然后选取其中的第一个

example:

>>> from scrapy import Selector>>> sel = Selector(text="""....:     
    ....:
  • 1
  • ....:
  • 2
  • ....:
  • 3
  • ....:
....:
    ....:
  • 4
  • ....:
  • 5
  • ....:
  • 6
  • ....:
""")>>> xp = lambda x: sel.xpath(x).extract()

获得父节点中的第一个 <li> 标签

>>> xp("//li[1]")[u'
  • 1
  • ', u'
  • 4
  • ']

    获得document中所有 <li> 标签的第一个 <li>

    >>> xp("(//li)[1]")[u'
  • 1
  • ']

    获得在以 <ul> 作为父节点的 所有的第一个 <li>

    >>> xp("//ul/li[1]")[u'
  • 1
  • ', u'
  • 4
  • ']

    获得document 中所有以 <ul> 作为父节点的 <li> 节点的第一个 <li>

    >>> xp("(//ul/li)[1]")[u'
  • 1
  • ']

    3. 当通过class查询的时候, 考虑使用CSS

    因为一个元素可能含有多个CSS class,用XPath的方式选择元素会很冗长:

    *[contains(concat(' ', normalize-space(@class), ' '), ' someclass ')]

    如果使用@class='someclass'可能会遗漏含有其他class的元素,如果使用contains(, 'someclass')去补偿的话,会发现其中包含了多余的含有相同的someclass的元素。

    因此,scrapy允许链式使用选择器,因此多数情况下你可以先用CSS选择class,再使用XPath:

    >>> from scrapy import Selector>>> sel = Selector(text='
    ')>>> sel.css('.shout').xpath('./time/@datetime').extract()[u'2014-07-23 19:00']

    转载于:https://my.oschina.net/whitejavadog/blog/817077

    你可能感兴趣的文章
    Homework Exercises 1
    查看>>
    bzoj 3670 [Noi2014]动物园
    查看>>
    bzoj 1009 [HNOI2008]GT考试——kmp+矩阵优化dp
    查看>>
    使用PHP输出中文JSON字符串
    查看>>
    用Curl测试POST
    查看>>
    Rails: No such file or directory - getcwd
    查看>>
    算法18-----判断是否存在符合条件的元素【list】
    查看>>
    运行TestCase时,提示:Element is not currently visible and so may not be interacted with
    查看>>
    将xml文件转为c#对像
    查看>>
    stl之map 排序
    查看>>
    gdb调试python
    查看>>
    为文本数据创建索引
    查看>>
    我发起并创立了一个 Javascript 前端库 开源项目 jWebForm
    查看>>
    再见 异步回调, 再见 Async Await, 10 万 个 协程 的 时代 来 了
    查看>>
    Intellij Idea编译项目下的.java文件时的编码问题
    查看>>
    MS Server数据库里的Char,VarChar,NChar,NVarChar数据类型的异同
    查看>>
    百度地图3.1.0(二)基于MapFragment的基本地图
    查看>>
    第二次实验
    查看>>
    flex4.5生成验证码
    查看>>
    Mysql5.7 - 一键安装脚本
    查看>>