爬蟲知識3:seletors選擇器、Xpath、 BeautifulSoup使用案例
本文主要介紹了Scrapy常用的資料提取的方法,包括seletors、scrapy shell、xpath、css、BeautifulSoup的使用方法及案例。只要掌握xpath或者css任意一種即可。
1、seletors選擇器
1)介紹
Scrapy提取資料有自己的一套機制。它們被稱作選擇器(seletors),構建於lxml庫之上,通過特定的XPath或者CSS表示式來等“選擇” HTML檔案中的某個部分。Selector有四個基本的方法,最常用的還是xpath:
XPath(query):傳入Xpath表示式queery,返回該表示式對應的所有節點的selector list。Xpath是一門在 XML 文件中查詢資訊的語言。XPath 可用來在 XML 文件中對元素和屬性進行遍歷。
css(query):傳入css表示式query,返回該表示式所對應的所有節點的selector list列表CSS是將HTML文件樣式化的語言。選擇器由它定義,並與特定的HTML元素的樣式相關聯。
re(): 根據傳入的正則表示式對資料進行提取,返回Unicode字串list列表
extract(): 序列化該節點為Unicode字串並返回list
2)匯入seletors
from scrapy.selector import Selector, HtmlXPathSelector
from scrapy.http import HtmlResponse
3)常用xpath使用方法:
常用語法:
/:根節點
//xxx/zzz:路徑
//div:去全域性的子孫中找所有的div元素
.//表示去當前物件的子孫中找
/xxx//div:去兒子物件中找xxx節點下所有的div元素
*:匹配任意節點元素
/html/body/div[1]:選取body下的第一個div節點
//div[@class="xxx"]:選取class屬性為xxx的div節點
//@attr:獲取attr對應的值
常用函式:
text():提取文字資訊,//*[@class='xxx']/text()
position():選取第幾個節點,//*[position()=1]
last():選取最後一個節點,//*[last()]
starts-with(@attr,substr):attr屬性值開頭substr的節點
contains(@attr,substr):attr屬性值是否包含substr
運算子:
|:計算兩個節點集合,比如//div|//li
比較運算子=,!=,<=...,比如//price[text()>10]
算數運算子:+,-,*,div,比如//price[text()+1]
邏輯運算子:or,and,[@class='xxxx' or @class='yyyy']
4)xpath語法案例:以取a標籤為案例,div、span等都相同
xpath('//a'):找到全域性中所有的a標籤
xpath('//a/text() '):獲取a標籤的文字值
xpath('//a/span'):a標籤物件兒子下的span標籤
xpath('//a[2]'):a標籤找到後,返回的是一個列表,[n]列表的n位置的值
xpath('//a[@id]'):找全域性中屬性為id的a標籤
xpath('//a[@id="i1"]'):找全域性中屬性id為i1的a標籤
xpath('//a/@id'):取a標籤的id的屬性值
xpath('//a[@href="link.html"][@id="i1"]'):兩個[]代表雙條件,需要href="link.html“,且id="i1"的a標籤
xpath('//a[contains(@href, "link")]'):a標籤的href需要包含"link"字元
xpath('//a[starts-with(@href, "link")]'):a標籤的href需要以"link"開頭
xpath('//a[re:test(@id, "i\d+")]'):正則表示式的寫法,需要有re:test
xpath('//a[re:test(@id, "i\d+")]/@href').extract(),正則表示式的寫法案例
xpath(.//)在當前基礎上往下找,需要加“.”,比如用在for迴圈中
obj.extract()#列表中的每一個物件轉化字串==>返回一個列表
obj.extract_first() #列表中的每一個物件轉化字元==>列表中的第一個元素
xpath('/html/body/ul/li/a/@href').extract():一層層去找標籤
5)獲取程式碼,需要在頁面,右鍵-----檢查元素---去看下html結構。
也可以直接選擇自己想要的內容,通過copy---copy xpath直接獲得原始碼,去貼上即可。
比如選取下面頁面的肖申克救贖的資訊:但一般這種路徑都會特別長。
//*[@id="content"]/div/div[1]/ol/li[1]/div/div[2]/div[1]/a/span[1]
6)css語法
基本語法:
.classvalue:選擇class屬性為classvalue的元素
#idvalue:選擇id值為idvalue的元素
p:選擇所有的p元素
div,p:選擇所有的div和p元素
div~p:前面有div元素的每個p元素,div和p為兄弟節點
li span :選擇li內部所有的span元素
div>p:選擇父結點為div的所有p元素
::text/::attr(src):文字資訊/提取某個屬性的值,比如a::attr(href),提取超連結
屬性的語法:
[attr]選擇所有帶attr屬性的元素
[attr=val]選擇attr值為val的所有元素:[numvalue=num1]
[attr^=val]選擇attr屬性值以val開頭的元素:[src^=http]
[attr$=val]選擇attr屬性值以val結尾的元素:[src^=.jpg]
[attr*=val]選擇attr屬性值包含val的元素:[src*=douban]
ele語法:
ele:first-of-type:所有子元素為ele的第一個元素
ele:first-child:第一個元素為ele的元素
ele:only-of-type:型別為ele的元素
ele:only-child:唯一子元素的每個ele元素
ele:nth-of-type(n):選擇第n個ele元素
ele:nth-child(n):第n個子元素為ele的元素
ele:last-child:最後一個為ele的子元素
2、Scrapy shell互動,測試網頁程式碼
Scrapy終端是一個互動終端shell,我們可以在未啟動spider的情況下嘗試及除錯程式碼,也可以用來測試XPath或CSS表示式,檢視他們的工作方式,方便我們爬取的網頁中提取的資料。一旦你習慣使用了Scrapy shell,你將會發現Scrapy shell對於開發爬蟲是非常好用的一個測試工具。
1)啟動Scrapy shell,有三種方式請求url
1-1直接請求url:
首先需要cmd-----進入專案根目錄,然後填寫"scrapy shell +url(你需要訪問的頁面地址) ",如下所示,即可返回資訊。
會看到如下的資訊
比如輸入:response.xpath('//title')可以看到如下資訊:
Scrapy Shell根據下載的頁面會自動建立一些方便使用的物件,例如Response物件,以及Selector物件(對HTML及XML內容)。當shell載入後,將得到一個包含response資料的本地 response 變數。
輸入response.body將輸出response的包體。
輸入response.headers可以看到response的包頭。
輸入response.selector時,將獲取到一個response初始化的類Selector的物件,此時可以通過使用response.selector.xpath()或response.selector.css()來對response進行查詢。
Scrapy也提供了一些快捷方式, 例如 response.xpath()或response.css()同樣可以生效。
1-2請求url設定請求資訊,使用:scrapy shell -s name=value語句
比如直接設定代理USER_AGENT的語句:
1-3 在命令列直接請求url,利用fetch。
req=Request(url,header={})
r=fetch(url)
然後就可以看到response.url的資訊了。
2)測試xpath的使用語法:以豆瓣TOP250為例。
比如選取html:response.xpath('/html')
提取網頁的title:response.xpath('/html/head/title')
找到所有的a標籤,或找到body下所有的a標籤:response.xpath('//body//a')
找到body下所有的標籤
text()獲取電影名稱:response.xpath('//div[@class="hd"]//a/span[1]/text()').extract()
獲取所有的電影的連線:response.xpath('//div[@class="hd"]//a/@href').extract()
提取所有的電影評分:response.xpath('//span[@class="rating_num"]/text()').extract()
提取所有的電影評分,且限制評分。response.xpath('//span[@class="rating_num" and text()>9.4]/text()').extract()
提取頁碼:response.xpath('//span[@class="next"]//a/@href').extract()
3)測試CSS的使用案例:以豆瓣TOP250為例。
比如選取html:response.css('html')
提取網頁的title:response.css('html head title')
獲取body下所有的a :response.css('body a')
text()獲取所有的電影名稱:response.css('.title::text')
根據文件結構,可以寫成如下格式:response.css('.title::text')
也可以使用ele語法獲取電影名稱:response.css("[class='hd'] a span:first-of-type").extract()
獲取所有的電影的連線:response.css('.hd a::attr(href)').extract()
提取所有的電影的評分:response.css('.rating_num::text').extract()
提取圖片:response.css("[src$=jpg]").extract()
附錄::
附1、BeautifulSoup
BeautifulSoup是一個模組,該模組用於接收一個HTML或XML字串,然後將其進行格式化,之後就可以使用他提供的方法進行快速查詢指定元素,從而使得在HTML或XML中查詢指定元素變得簡單。
四大物件種類
Beautiful Soup將複雜HTML文件轉換成一個複雜的樹形結構,每個節點都是Python物件,所有物件可以歸納為4種:
Tag:HTML 中的一個個標籤,比如a,div等,有兩個屬性name和attrs
NavigableString:標籤內部的文字,可以用 .string獲得
BeautifulSoup:表示的是一個文件的全部內容
Comment:註釋
1)模組的安裝(需要cmd,進入到python的工作目錄)
pip3 install beautifulsoup4
2)匯入模組
from bs4 import BeautifulSoup
3)建立物件
soup=BeautifulSoup(response.text,'html.parser')
4)使用語法:
soup.find('a'):獲取匹配的第一個a標籤,a可以改成span、div等
soup.find_all('a'):獲取所有匹配的a標籤,是列表形式
soup.find_all(id='xx'):查詢屬性id為xx的所有節點
soup.find_all(div,class_='xx'):查詢class屬性為xx的所有div節點
soup.find_all(a,text='xx'):查詢text值為xx的所有a節點
soup.find_all(a,text=re.complite('xx')):正則查詢text值為xx的所有a節點
soup.find('a').has_attr('id'),其中has_attr,檢查標籤是否具有該屬性
soup.find('body').children:找到所有子標籤
soup.find('body').descendants:找到所有的子子孫孫標籤
soup.find('body').clear(),將標籤的所有子標籤全部清空(保留標籤名)
soup.find('body').decompose():decompose,遞迴的刪除所有的標籤
soup.find('body')..extract():解析標籤
soup.find('body').decode(),soup.find('body').decode_contents(),decode,轉換為字串(含當前標籤);decode_contents(不含當前標籤)
soup.find_all('a',limit=1),只拿第一個a標籤
soup.find_all(name='a', attrs={'class': 'sister'}, recursive=True, text='Lacie')限制屬性;等同於soup.find(name='a', class_='sister', recursive=True, text='Lacie');recursive=True代表查詢所有的節點,recursive=False代表只查詢本節點下的東西
soup.find_all(name=['a','div']),限制選取全部的a、div標籤
soup.find_all(href=['link1','link2']),選取href為link11、link2的標籤
soup.find_all(text=['Tillie']),text為Tillie的所有節點
soup.find_all(class_=['sister0', 'sister']),限制class=sister0、sister
正則表示式rep = re.compile('sister.*') ,v = soup.find_all(class_=rep)
soup.find('a').get_text,其中get_text獲取標籤內部文字內容
soup.find('br').is_empty_element,其中is_empty_element,是否是空標籤(是否可以是空)或者自閉合標籤,判斷是否是如下標籤:'br' , 'hr', 'input', 'img', 'meta','spacer', 'link', 'frame'。
soup.strings,獲取多個標籤內容
list(soup.stripped_strings),可以去除多餘空白內容
append在當前標籤內部追加一個標籤
5)使用soup.select()通過css進行篩選:
可參考css部分知識,僅舉部分案例
soup.select('a'):獲取匹配的a標籤
soup.select('div a'):按層級獲取div下的a標籤
soup.select('.css1'):查詢屬性值為css1的標籤
soup.select('#id1'):查詢id屬性值為#id1的標籤
soup.select('div[class]'):查詢存在某個屬性值的標籤
soup.select('div>p'):選擇父結點為div的所有p元素
soup.select('div~p'):前面有div元素的每個p元素,div和p為兄弟節點
soup.select('attr^=val'):屬性attr以val開頭的標籤
具體可參考:
http://www.cnblogs.com/wupeiqi/articles/6283017.html
5)使用案例:
from bs4 import BeautifulSoup
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
asdf
<div class="title">
<b>The Dormouse's story總共</b>
<h1>f</h1>
</div>
<div class="story">Once upon a time there were three little sisters; and their names were
<a class="sister0" id="link1">Els<span>f</span>ie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</div>
ad<br/>sf
<p class="story">...</p>
</body>
</html>
"""
#封裝使用案例:
soup = BeautifulSoup(html_doc, features="lxml")
tag1 = soup.find(name='a')
print('找到第一個a標籤',tag1)
tag2 = soup.find_all(name='a')
print('找到所有的a標籤',tag2)
tag3 = soup.select('#link2')
print('找到id=link2的標籤',tag3)
執行效果:
附2、XPath
XPath 是一門在 XML 文件中查詢資訊的語言。XPath用於在 XML文件中通過元素和屬性進行導航。
1、節點介紹:
在 XPath 中,有七種型別的節點:元素、屬性、文字、名稱空間、處理指令、註釋以及文件節點(或稱為根節點)。
如下例:
上面的XML文件中的節點例子:
<bookstore> (文件節點)
<author>J K. Rowling</author> (元素節點)
lang="en" (屬性節點)
2、節點關係:
父(Parent):每個元素以及屬性都有一個父。
在下面的例子中,book 元素是 title、author、year 以及 price 元素的父:
子(Children):元素節點可有零個、一個或多個子。
在下面的例子中,title、author、year 以及 price 元素都是 book 元素的子:
同胞(Sibling):擁有相同的父的節點
在下面的例子中,title、author、year 以及 price 元素都是同胞:
先輩(Ancestor):某節點的父、父的父,等等。
在下面的例子中,title 元素的先輩是 book 元素和 bookstore 元素:
後代(Descendant):某個節點的子,子的子,等等。
在下面的例子中,bookstore 的後代是 book、title、author、year 以及 price 元素:
3、XPath 語法
1)常用表示式:
以下例看使用案例:
xpath(‘bookstore’) 選取 bookstore元素的所有子節點。
xpath(‘/bookstore’),選取根元素
xpath(‘bookstore/book’),選取屬於 bookstore 的子元素的所有 book 元素。
xpath(‘//book’),全域性中找到所有的book元素,而不管它們在文件中的位置。
xpath(‘bookstore//book’) 選擇屬於bookstore元素的後代的所有 book 元素,而不管它們位於bookstore之下的什麼位置。
xpath(‘//@lang’) 選取名為 lang 的所有屬性。
xpath(‘ /bookstore/*’) 選取 bookstore 元素的所有子元素。
xpath(‘ //*’) 選取文件中的所有元素。
xpath(‘ //title[@*]’) 選取所有帶有屬性的 title 元素。
通過在路徑表示式中使用“|”運算子,您可以選取若干個路徑。
//book/title | //book/price 選取 book 元素的所有 title 和 price 元素。
//title | //price 選取文件中的所有 title 和 price 元素。
/bookstore/book/title | //price 選取屬於 bookstore元素的book元素的所有title元素,以及文件中所有的price元素。
2)謂語
謂語用來查詢某個特定的節點或者包含某個指定的值的節點。謂語被嵌在方括號中。
比如以下用法: