scrapy 實戰 使用 內置 xpath css 取值 欄目 Python 简体版
原文   原文鏈接

 

 
以伯樂在線文章爲爬取目標blog.jobbole.com,發如今"最新文章"選項中可看到全部文章
 
通常來講,能夠用scrapy中自帶的xpath或者css來提取數據,定義在spiders/jobbole.py中的def parse(self, response)
import scrapy class JobboleSpider(scrapy.Spider): name = '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 評論 ', '面試']
相關文章
相關標籤/搜索
每日一句
    每一个你不满意的现在,都有一个你没有努力的曾经。
本站公眾號
   歡迎關注本站公眾號,獲取更多信息