1. Selectors選擇器
在抓取網頁時,您需要執行的最常見任務是從HTML源提取數據。有幾個庫可用於實現此目的,例如:
- BeautifulSoup是Python程序員中非常流行的Web抓取庫,它基於HTML代碼的結構構造Python對象,並且相當好地處理壞標記,但它有一個缺點:它很慢。
- lxml是一個XML解析庫(也可以解析HTML),它使用基於ElementTree的pythonic API 。(lxml不是Python標准庫的一部分。)
Scrapy帶有自己的提取數據機制。它們被稱為選擇器,因為它們“選擇”由XPath或CSS表達式指定的HTML文檔的某些部分。
XPath是一種用於在XML文檔中選擇節點的語言,也可以與HTML一起使用。CSS是一種將樣式應用於HTML文檔的語言。它定義選擇器以將這些樣式與特定HTML元素相關聯。
Selector是基於lxml來構建的,支持XPath選擇器、CSS選擇器以及正則表達式,功能全面,解析速度和准確度非常高。
2. 選擇器使用
1.通過response響應對象屬性.selector構建選擇器實例
response.selector.xpath('//span/text()').get()
使用XPath和CSS查詢響應非常常見,響應包括另外兩個快捷方式:response.xpath()和response.css():
>>> response.xpath('//span/text()').get() 'good' >>> response.css('span::text').get() 'good'
2.直接使用Selectors構建
從HTML文本構造
>>> from scrapy.selector import Selector >>> body = '<html><body><span>good</span></body></html>' >>> Selector(text=body).xpath('//span/text()').get() 'good'
從響應構造
>>> from scrapy.selector import Selector >>> from scrapy.http import HtmlResponse >>> response = HtmlResponse(url='http://example.com', body=body) >>> Selector(response=response).xpath('//span/text()').get() 'good'
3. CSS選擇器
基礎選擇器
選擇器 | 含義 |
* | 通用元素選擇器,匹配頁面任何元素(這也就決定了我們很少使用) |
#id | id選擇器,匹配特定id的元素 |
.class | 類選擇器,匹配class包含(不是等於)特定類的元素 |
element | 標簽選擇器 根據標簽選擇元素 |
[attr] | 屬性選擇器 根據元素屬性去選擇 |
組合選擇器
選擇器 | 示例 | 示例說明 | 含義 |
elementE,elementF | div,p | 選擇所有<div>元素和<p>元素 | 多元素選擇器,用”,分隔,同時匹配元素E或元素F |
elementE elementF | div p | 選擇<div>元素內的所有<p>元素 | 后代選擇器,用空格分隔,匹配E元素所有的后代(不只是子元素、子元素向下遞歸)元素F |
elementE>elementF | div>p | 選擇所有父級是 <div> 元素的 <p> 元素 | 子元素選擇器,用”>”分隔,匹配E元素的所有直接子元素 |
elementE+elementF | div+p | 選擇所有緊接着<div>元素之后的<p>元素 | 直接相鄰選擇器,匹配E元素之后的相鄰的同級元素F |
elementE~elementF | p~ul | 選擇p元素之后的每一個ul元素 | 普通相鄰選擇器,匹配E元素之后的同級元素F(無論直接相鄰與否) |
.class1.class2 | .user.login | 匹配如<div class="user login">元素 | 匹配類名中既包含class1又包含class2的元素 |
CSS選擇器是前端的基礎,以上只給了比較重要的內容,具體CSS選擇器內容可以去w3school參考
Scrapy中CSS選擇器的拓展
根據W3C標准,CSS選擇器不支持選擇文本節點或屬性值。但是在Web抓取環境中選擇這些是非常重要的,Scrapy(parsel)實現了一些非標准的偽元素
- 要選擇文本節點,使用
::text
- 選擇屬性值,用
::attr(name) name
是指你想要的價值屬性的名稱
#沒有用::text,對selectors對象使用get方法后,返回的是匹配的html元素 >>> response.css('title').get() <title>Example website</title> #使用::text就是返回標簽內的文本 >>> response.css('title::text').get() 'Example website' #<a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a> 使用a::attr(href)可以提取屬性 >>>response.css('a::attr(href)').get() 'image1.html'
4. XPath
XPath,全稱 XML Path Language,即 XML 路徑語言,它是一門在XML文檔中查找信息的語言。XPath 最初設計是用來搜尋XML文檔的,但是它同樣適用於 HTML 文檔的搜索。
1.XPath 使用路徑表達式在 XML 文檔中選取節點。節點是通過沿着路徑或者 step 來選取的。 下面列出了最有用的路徑表達式
表達式 | 描述 |
---|---|
nodename | 選取此節點的所有子節點。 |
/ | 從根節點選取。 |
// | 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。 |
. | 選取當前節點。 |
.. | 選取當前節點的父節點。 |
@ | 選取屬性。 |
舉例如下
路徑表達式 | 結果 |
---|---|
bookstore | 選取 bookstore 元素的所有子節點。 |
/bookstore | 選取根元素 bookstore。 注釋:假如路徑起始於正斜杠( / ),則此路徑始終代表到某元素的絕對路徑! |
bookstore/book | 選取屬於 bookstore 的子元素的所有 book 元素。 |
//book | 選取所有 book 子元素,而不管它們在文檔中的位置。 |
bookstore//book | 選擇屬於 bookstore 元素的后代的所有 book 元素,而不管它們位於 bookstore 之下的什么位置。 |
//@lang | 選取名為 lang 的所有屬性。 |
2.謂語用來查找某個特定的節點或者包含某個指定的值的節點。謂語被嵌在方括號中。
路徑表達式 | 結果 |
---|---|
/bookstore/book[1] | 選取屬於 bookstore 子元素的第一個 book 元素。 |
/bookstore/book[last()] | 選取屬於 bookstore 子元素的最后一個 book 元素。 |
/bookstore/book[last()-1] | 選取屬於 bookstore 子元素的倒數第二個 book 元素。 |
/bookstore/book[position()<3] | 選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 選取所有擁有名為 lang 的屬性的 title 元素。 |
//title[@lang='eng'] | 選取所有 title 元素,且這些元素擁有值為 eng 的 lang 屬性。 |
/bookstore/book[price>35.00] | 選取 bookstore 元素的所有 book 元素,且其中的 price 元素的值須大於 35.00。 |
/bookstore/book[price>35.00]/title | 選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大於 35.00。 |
3.選取未知節點
通配符 | 描述 |
---|---|
* | 匹配任何元素節點。 |
@* | 匹配任何屬性節點。 |
node() | 匹配任何類型的節點。 |
實例如下:
路徑表達式 | 結果 |
---|---|
/bookstore/* | 選取 bookstore 元素的所有子元素。 |
//* | 選取文檔中的所有元素。 |
//title[@*] | 選取所有帶有屬性的 title 元素。 |
同樣scrapy也給XPath拓展了方法,使用.//text()可以選擇文本
摘自https://www.w3school.com.cn/xpath/xpath_syntax.asp
5. .xpath()和.css()方法
css(query)
應用給定的CSS選擇器並返回一個SelectorList實例。(SelectorList實例可以理解為Selector組成的list)
query 是一個包含要應用的CSS選擇器的字符串。
在后台,CSS查詢使用cssselect庫和run .xpath()方法轉換為XPath查詢 。
>>> response.css("link") [<Selector xpath='descendant-or-self::link' data='<link rel="alternate" type="text/html" h'>, <Selector xpath='descendant-or-self::link' data='<link rel="next" type="application/atom+'>, ...
xpath(query, namespaces=None, **kwargs)
查找與xpath匹配的節點query,並將結果作為SelectorList實例返回, 並將所有元素展平。List元素也實現了Selector接口。
query 是一個包含要應用的XPATH查詢的字符串。
namespaces是一個可選的映射(dict),用於注冊的人的附加前綴。相反,這些前綴不會保存以供將來調用。
>>> response.xpath("//link") [<Selector xpath='//link' data='<link rel="alternate" type="text/html" h'>, <Selector xpath='//link' data='<link rel="next" type="application/atom+'>, ...
串聯查詢
由於css()與xpath()方法返回SelectorList實例,並且SelectorList實例也有與Selector對象相同的方法(SelectorList實例的方法可以理解為list中所有Selector遍歷執行),所以可以在返回結果上繼續查詢
response.css(".quote").css("small") #這個就是先查找出所有class=quote的元素,然后在這些元素中查找small標簽元素
6. .get()與.getall()
get()
以unicode字符串返回第一個真實的數據,沒有css xpath拓展方法(::text ::attr //text()),就返回匹配的html元素數據
getall()
以unicode字符串list返回所有數據,其它同get()一樣
默認返回值
如果沒有匹配到元素則返回None,但是可以提供默認返回值作為參數,以代替None
>>> response.xpath('//div[@id="not-exists"]/text()').get(default='not-found') 'not-found'
.get() .getall()與extract() extract_first()
SelectorList.get()與SelectorList.extract_first()實際是一樣的,同理SelectorList.getall()與SelectorList.extract()相同
7. Selector其他屬性方法
.attrib
返回底層元素的屬性字典
>>> response.css('img').attrib['src'] 'image1_thumb.jpg'
re(regex,replace_entities = True )
Selector還有一種.re()使用正則表達式提取數據的方法。但是,與 .xpath()或 .css()不同,.re()返回unicode字符串列表。所以你不能構造嵌套的.re()調用。
>>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)') ['My image 1', 'My image 2', 'My image 3', 'My image 4', 'My image 5']