【Scrapy】 selector 学习记录二(re,set)
2017-01-01 00:00
471 查看
正则表达式(re)
在 xpath 中的 starts-with() 或者 contians() 无效时 ,可以采用 re 的 test() 函数。例如:
>>> from scrapy import Selector >>> doc = """ ... <div> ... <ul> ... <li class="item-0"><a href="link1.html">first item</a></li> ... <li class="item-1"><a href="link2.html">second item</a></li> ... <li class="item-inactive"><a href="link3.html">third item</a></li> ... <li class="item-1"><a href="link4.html">fourth item</a></li> ... <li class="item-0"><a href="link5.html">fifth item</a></li> ... </ul> ... </div> ... """ >>> 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)(来自http://schema.org/Product的样本内容):
>>> doc = """ ... <div itemscope itemtype="http://schema.org/Product"> ... <span itemprop="name">Kenmore White 17" Microwave</span> ... <img src="kenmore-microwave-17in.jpg" alt='Kenmore 17" Microwave' /> ... <div itemprop="aggregateRating" ... itemscope itemtype="http://schema.org/AggregateRating"> ... Rated <span itemprop="ratingValue">3.5</span>/5 ... based on <span itemprop="reviewCount">11</span> customer reviews ... </div> ... ... <div itemprop="offers" itemscope itemtype="http://schema.org/Offer"> ... <span itemprop="price">$55.00</span> ... <link itemprop="availability" href="http://schema.org/InStock" />In stock ... </div> ... ... Product description: ... <span itemprop="description">0.7 cubic feet countertop microwave. ... Has six preset cooking categories and convenience features like ... Add-A-Minute and Child Lock.</span> ... ... Customer reviews: ... ... <div itemprop="review" itemscope itemtype="http://schema.org/Review"> ... <span itemprop="name">Not a happy camper</span> - ... by <span itemprop="author">Ellie</span>, ... <meta itemprop="datePublished" content="2011-04-01">April 1, 2011 ... <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating"> ... <meta itemprop="worstRating" content = "1"> ... <span itemprop="ratingValue">1</span>/ ... <span itemprop="bestRating">5</span>stars ... </div> ... <span itemprop="description">The lamp burned out and now I have to replace ... it. </span> ... </div> ... ... <div itemprop="review" itemscope itemtype="http://schema.org/Review"> ... <span itemprop="name">Value purchase</span> - ... by <span itemprop="author">Lucas</span>, ... <meta itemprop="datePublished" content="2011-03-25">March 25, 2011 ... <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating"> ... <meta itemprop="worstRating" content = "1"/> ... <span itemprop="ratingValue">4</span>/ ... <span itemprop="bestRating">5</span>stars ... </div> ... <span itemprop="description">Great microwave for the price. It is small and ... fits in my apartment.</span> ... </div> ... ... ... </div> ... """
>>> 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() ... print current 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='<a href="#">Click here to go to the <strong>Next Page</strong></a>')
把一个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'<a href="#">Click here to go to the <strong>Next Page</strong></a>'] >>> 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'<a href="#">Click here to go to the <strong>Next Page</strong></a>']
2. 注意 //node[1] 和(//node)[1]的区别
//node[1] 选择它们的父节点的第一个子节点(occurring first under their respective parents)(//node)[1] 选择文档中的所有node,然后选取其中的第一个
example:
>>> from scrapy import Selector >>> sel = Selector(text=""" ....: <ul class="list"> ....: <li>1</li> ....: <li>2</li> ....: <li>3</li> ....: </ul> ....: <ul class="list"> ....: <li>4</li> ....: <li>5</li> ....: <li>6</li> ....: </ul>""") >>> xp = lambda x: sel.xpath(x).extract()
获得父节点中的第一个 <li> 标签
>>> xp("//li[1]") [u'<li>1</li>', u'<li>4</li>']
获得document中所有 <li> 标签的第一个 <li>
>>> xp("(//li)[1]") [u'<li>1</li>']
获得在以 <ul> 作为父节点的 所有的第一个 <li>
>>> xp("//ul/li[1]") [u'<li>1</li>', u'<li>4</li>']
获得document 中所有以 <ul> 作为父节点的 <li> 节点的第一个 <li>
>>> xp("(//ul/li)[1]") [u'<li>1</li>']
3. 当通过class查询的时候, 考虑使用CSS
因为一个元素可能含有多个CSS class,用XPath的方式选择元素会很冗长:*[contains(concat(' ', normalize-space(@class), ' '), ' someclass ')]
如果使用@class='someclass'可能会遗漏含有其他class的元素,如果使用contains(@class, 'someclass')去补偿的话,会发现其中包含了多余的含有相同的someclass的元素。
因此,scrapy允许链式使用选择器,因此多数情况下你可以先用CSS选择class,再使用XPath:
>>> from scrapy import Selector >>> sel = Selector(text='<div class="hero shout"><time datetime="2014-07-23 19:00">Special date</time></div>') >>> sel.css('.shout').xpath('./time/@datetime').extract() [u'2014-07-23 19:00']
相关文章推荐
- 【Scrapy】 selector 学习记录一(xpath、css)
- 爬虫框架Scrapy学习记录II--Selector学习
- 【Scrapy】 selector 学习记录三(Selector详细介绍)
- 【Scrapy】学习记录3_编写简单爬虫
- [学习记录]多媒体音量控制setVolumeControlStream(int streamType)
- python学习记录--set
- DayDayUP_Python自学记录[5]_dict和set学习
- 廖雪峰JS教程学习记录----Map和Set
- SQL Server学习记录之set nocount on
- es6学习记录 object-prop-name/get set/static
- 【Scrapy】 Feed exports 学习记录四
- Scrapy爬虫学习中遇到的问题记录
- 20100507 学习记录: Server Error in '/' Application. Object reference not set to an instance of an object
- Scrapy学习记录
- 学习ios碰到[UITableViewCellContentView setImage:]: unrecognized selector sent to instance 0x7fa450440dc0
- python re complie 学习记录
- swift学习记录(selector)
- 2014.8.6学习Oracle记录:set autotrace on
- Redis学习记录之命令SortedSet(十三)
- 【Scrapy】学习记录1_一个基本的Scrapy项目