jobbole' allowed_domains = ['blog.jobbole.com'] start_urls = ['http://blog.jobbole.com/'] def parse(self, response): re_selector = response.xpath('//*[@id="post-110287"]/div[1]/h1/text()')

 

 
注意:由于jqury会生成额外的代码,咱们在源码看到的代码和页面加载以后显示的代码可能不一样,因此不要按层级一步步找,最好找到id,或者class来定位
 
小技巧:
1)当咱们使用class来定位标签时,能够在F12中用ctrl+F 查看这个class名字是否惟一
2)Xpath路径可右键直接复制
 
 
 
 
一. Xpath经常使用方法
 
1. 经常使用规则以下
 
//           从当前节点选取子孙节点,若是符号前面没路径,表示整个文档
/            从当前节点选取直接子节点
.             选取当前节点
..            选取当前节点父节点
@            选取属性
//*            整个HTML文本中的全部节点
 
 
例子1
<html><body><div>
<ul>
<li class="item-0"><a href="link1.html"><span>first item</span></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></body></html>
 

 

1. 获取父节点属性
首先选中href属性为link4.html的a节点,而后再获取其父节点,而后再获取其class属性 result1 = response.xpath('//a[@href="link4.html"]/../@class') 咱们也能够经过parent::来获取父节点 result2 = response.xpath('//a[@href="link4.html"]/parent::*/@class')
注意:
//a表示html中的全部a节点,他们的href属性有多个,这里[]的做用是属性匹配,找到a的href属性为link4.html的节点
 
 
2. 获取节点内部文本
获取class为item-1的li节点文本, result3 = response.xpath('//li[@class="item-0"]/a/text()') 返回结果为['first item', 'fifth item']

 

 
3. 属性获取
获取全部li节点下的全部a节点的href属性 result4 = response.xpath('//li/a/@href') 返回结果为['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']

 

 
4. 按序选择
result = response.xpath('//li[1]/a/text()') #选取第一个li节点 result = response.xpath('//li[last()]/a/text()') #选取最后一个li节点 result = response.xpath('//li[position()<3]/a/text()') #选取位置小于3的li节点,也就是1和2的节点 result = response.xpath('//li[last()-2]/a/text()')  #选取倒数第三个节点

 

 
5. 节点轴选择
1)返回第一个li节点的全部祖先节点,包括html,body,div和ul result = response.xpath('//li[1]/ancestor::*') 2)返回第一个li节点的<div>祖先节点 result = response.xpath('//li[1]/ancestor::div') 3)返回第一个li节点的全部属性值 result = response.xpath('//li[1]/attribute::*') 4)首先返回第一个li节点的全部子节点,而后加上限定条件,选组href属性为link1.html的a节点 result = response.xpath('//li[1]/child::a[@href="link1.html"]') 5)返回第一个li节点的全部子孙节点,而后加上只要span节点的条件 result = response.xpath('//li[1]/descendant::span') 6)following轴可得到当前节点以后的全部节点,虽然使用了*匹配,可是又加了索引选择,因此只获取第2个后续节点,也就是第2个<li>节点中的<a>节点 result = response.xpath('//li[1]/following::*[2]') 7)following-sibling可获取当前节点以后的全部同级节点,也就是后面全部的<li>节点 result = response.xpath('//li[1]/following-sibling::*')

 

 
6. 属性多值匹配
<li class="li li-first"><a href="link.html">first item</a></li> result5 = response.xpath('//li[@class="li"]/a/text()') 返回值为空,由于这里HTML文本中li节点为class属性有2个值li和li-first,若是还用以前的属性匹配就不行了,须要用contain()函数 正确方法以下 result5 = response.xpath('//li[contains(@class, "li")]/a/text()') contains()方法中,第一个参数为属性名,第二个参数传入属性值,只要此属性名包含所传入的属性值就可完成匹配

 

 
 7.  多属性匹配,这里说一下不用框架的时候,xpath的常规用法
有时候咱们须要多个属性来肯定一个节点,那么就须要同时匹配多个属性,可用and来链接
from lxml import etree text = ''' <li class = "li li-first" name="item"><a href="link.html">first item</a></li>
''' html = etree.HTML(text) result6 = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()') print(result)
这里的li节点有class和name两个属性,须要用and操做符相连,而后置于中括号内进行条件筛选
 
 
 
 
 
二. 调试命令
cmd中执行以下代码,便可进入调试命令行,这个命令已经取得了页面中的原代码,命令测试成功后便可放在def parse函数中
 
scrapy shell http://blog.jobbole.com/110287
开始调试,
1. 取得文章标题
>>> title = response.xpath('//div[@class="entry-header"]/h1/text()') >>> title [<Selector xpath='//div[@class="entry-header"]/h1/text()' data='2016 腾讯软件开发面试题(部分)'>] >>> title.extract() ['2016 腾讯软件开发面试题(部分)'] >>> title.extract()[0] '2016 腾讯软件开发面试题(部分)'
>>> title.extract_first() '2016 腾讯软件开发面试题(部分)'
说明
1)extract()方法会把原数据的selector类型转变为列表类型
2)extract()会获得多个值,extract()[1]取第2个值
3)extract_first()获得第一个值,类型为字符串。extract_first(default='')若是没取到返回默认值
 
 
2. 取得发表日期
>>> response.xpath("//p[@class='entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·","").strip() '2017/02/18'
 

 

3. 点赞数,span标签里有不少class名,选一个看起来像惟一的,测试一下,而后用contains()函数简化操做
>>> response.xpath("//span[contains(@class, 'vote-post-up')]/h10/text()").extract() ['2'] >>> response.xpath("//span[contains(@class, 'vote-post-up')]/h10/text()").extract()[0] '2'
>>> int(response.xpath("//span[contains(@class, 'vote-post-up')]/h10/text()").extract()[0]) 2

 

 
4. 收藏数,要用正则,re模块也是scrapy的内置模块,注意要用非贪婪匹配,不然只会取到8
>>> response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").extract()[0] ' 28 收藏'
>>> string = response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").extract()[0] >>> import re >>> pattern = re.match(".*?(\d+).*", string) >>> pattern.group(1) '28'

 能够简写为css

>>> response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").re('.*?(\d+).*')
['28']
>>> response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").re('.*?(\d+).*')[0]
'28'

 

 

5. 使用列表推导式取得一个标签中的部分元素,以下取得职场和面试字样。适用于有些文章没评论标签的状况
找到不是以"评论"结尾的元素 >>> response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract() ['职场', ' 9 评论 ', '面试'] >>> tag_list = response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract() >>> [element for element in tag_list if not element.strip().endswith("评论")] ['职场', '面试'] >>> tag_choose=[element for element in tag_list if not element.strip().endswith("评论")] >>> tags=",".join(tag_choose) >>> tags '职场,面试'

 

join()函数基本语法: 'sep'.join(seq)。表示以sep为分隔符,将seq中全部的元素合并成一个新的字符串
sep表示分隔符,能够为空;
seq表示要链接的数据,数据类型能够是列表,字符串,元组或者字典
 
 
 
 
三. css提取方式
 
1. css的几个选择器
 
li a 
选取全部li下的全部a节点
ul + p
选择ul后面的第一个p元素,ul和p是兄弟节点
div#container>ul
选取id为container的div标签,下边的第一个ul子元素
ul ~ p 
选取与ul相邻的全部p元素
a[title] 
选取全部含有title属性的a元素
a::attr(href)
获取全部a元素的href属性值
a[href="http://jobbole.com"] 
选取全部href属性为http://jobbole.com值的a元素
a[href*="jobble"]  
选取全部href属性包含jobbole的a元素
a[href^="http"]
选取全部href属性值以http开头的a元素
a[href$=".jpg"]  
选取全部href属性值以.jpg结尾的a元素
input[type=radio]:checked      
选择选中的radio的元素
div:not(#container) 
选取全部id不等于container的div元素
li:nth-child(3)     
选取第三个li元素
tr:nth-child(2n)      
选取偶数位的tr元素
 
 
 
2. scrapy shell中使用css来提取数据
scrapy shell http://blog.jobbole.com/110287
 
1)提取标题,须要用到css的伪类 ::text
>>> response.css(".entry-header h1").extract() ['<h1>2016 腾讯软件开发面试题(部分)</h1>'] >>> response.css(".entry-header h1::text").extract()[0] '2016 腾讯软件开发面试题(部分)'
 

 

2)文章建立时间
>>> response.css("p.entry-meta-hide-on-mobile::text").extract()[0].strip().replace(" ·","") '2017/02/18'
注意:这里p和类名之间没空格,表示类名为entry-meta-hide-on-mobile的p元素
 
 
3)点赞数,对于属性多值匹配用css会很方便
>>> response.css(".vote-post-up h10::text").extract()[0] '2'

 

 
4) 收藏数,注意转义字符的方向
>>> response.css(".bookmark-btn::text").extract()[0] ' 28 收藏'
>>> string = response.css(".bookmark-btn::text").extract()[0] >>> tag=re.match(".*?(\d+).*", string) >>> tag.group(1) '28'

 

其实正则re也是scrapy的内置模块,能够简写为以下html

>>> response.css(".bookmark-btn::text").re('.*?(\d+).*')
['28']
>>> response.css(".bookmark-btn::text").re('.*?(\d+).*')[0]
'28'

 

 

 
5) 提取正文内容,通常把格式也取出来
response.css("div.entry").extract()[0]

 

 
6)  取得职场,评论,面试字样
>>> response.css("p.entry-meta-hide-on-mobile a::text").extract() ['职场', ' 9 评论 ', '面试']