博客
关于我
强烈建议你试试无所不能的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

    你可能感兴趣的文章
    算法优化:rgb向yuv的转化最优算法,快得让你吃惊!
    查看>>
    [Android开发常见问题-11] Unable to execute dex: Multiple dex files define 解决方法
    查看>>
    CF 332A Down the Hatch! 超级水题。。不过题目太长了
    查看>>
    Oracle—RMAN备份(一)
    查看>>
    php ceil() 函数向上舍入为最接近的整数。
    查看>>
    python开发_json_一种轻量级的数据交换格式
    查看>>
    Chrome 控制台新玩法-console显示图片以及为文字加样式
    查看>>
    JSAPI用户手册
    查看>>
    C关系运算结果及逻辑运算结果保存
    查看>>
    android开发(25) - 推送的实现,使用百度云推送
    查看>>
    SCPD
    查看>>
    mac下配置android环境变量
    查看>>
    使用sphinx生成Python文档
    查看>>
    项目管理--时间管理
    查看>>
    sp_executesql动态执行sql语句并将结果赋值给一变量
    查看>>
    AndroidManifest.xml文件详解
    查看>>
    【转】self.myOutlet=nil、viewDidUnload、dealloc的本质剖析
    查看>>
    jQuery性能优化整理
    查看>>
    2013第45周五准备考试
    查看>>
    如果返回结构体类型变量(named return value optimisation,NRVO) ------ 续
    查看>>