在使用Python本爬蟲採集數據時,一個很重要的操做就是如何從請求到的網頁中提取數據,而正肯定位想要的數據又是第一步操做。css
本文將對比幾種 Python 爬蟲中比較經常使用的定位網頁元素的方式供你們學習
1.傳統 BeautifulSoup 操做
2.基於 BeautifulSoup 的 CSS 選擇器(與 PyQuery 相似)
3.XPath
4.正則表達式html
參考網頁是噹噹網圖書暢銷總榜:python
http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1
咱們以獲取第一頁 20 本書的書名爲例。先肯定網站沒有設置反爬措施,是否能直接返回待解析的內容:正則表達式
import requests url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text print(response)
仔細檢查後發現須要的數據都在返回內容中,說明不須要特別考慮反爬舉措瀏覽器
審查網頁元素後能夠發現,書目信息都包含在 li 中,從屬於 class 爲 bang_list clearfix bang_list_mode 的 ul 中ruby
進一步審查也能夠發現書名在的相應位置,這是多種解析方法的重要基礎學習
經典的 BeautifulSoup 方法藉助 from bs4 import BeautifulSoup,而後經過 soup = BeautifulSoup(html, "lxml") 將文本轉換爲特定規範的結構,利用 find 系列方法進行解析,代碼以下:網站
import requests from bs4 import BeautifulSoup url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text def bs_for_parse(response): soup = BeautifulSoup(response, "lxml") li_list = soup.find('ul', class_='bang_list clearfix bang_list_mode').find_all('li') # 鎖定ul後獲取20個li for li in li_list: title = li.find('div', class_='name').find('a')['title'] # 逐個解析獲取書名 print(title) if __name__ == '__main__': bs_for_parse(response)
成功獲取了 20 個書名,有些書面顯得冗長能夠經過正則或者其餘字符串方法處理,本文不做詳細介紹url
這種方法實際上就是 PyQuery 中 CSS 選擇器在其餘模塊的遷移使用,用法是相似的。關於 CSS 選擇器詳細語法能夠參考:http://www.w3school.com.cn/cssref/css_selectors.asp因爲是基於 BeautifulSoup 因此導入的模塊以及文本結構轉換都是一致的:spa
import requests from bs4 import BeautifulSoup url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text def css_for_parse(response): soup = BeautifulSoup(response, "lxml") print(soup) if __name__ == '__main__': css_for_parse(response)
而後就是經過 soup.select 輔以特定的 CSS 語法獲取特定內容,基礎依舊是對元素的認真審查分析:
import requests from bs4 import BeautifulSoup from lxml import html url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text def css_for_parse(response): soup = BeautifulSoup(response, "lxml") li_list = soup.select('ul.bang_list.clearfix.bang_list_mode > li') for li in li_list: title = li.select('div.name > a')[0]['title'] print(title) if __name__ == '__main__': css_for_parse(response)
XPath 即爲 XML 路徑語言,它是一種用來肯定 XML 文檔中某部分位置的計算機語言,若是使用 Chrome 瀏覽器建議安裝 XPath Helper 插件,會大大提升寫 XPath 的效率。
以前的爬蟲文章基本都是基於 XPath,你們相對比較熟悉所以代碼直接給出:
import requests from lxml import html url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text def xpath_for_parse(response): selector = html.fromstring(response) books = selector.xpath("//ul[@class='bang_list clearfix bang_list_mode']/li") for book in books: title = book.xpath('div[@class="name"]/a/@title')[0] print(title) if __name__ == '__main__': xpath_for_parse(response)
若是對 HTML 語言不熟悉,那麼以前的幾種解析方法都會比較吃力。這裏也提供一種萬能解析大法:正則表達式,只須要關注文本自己有什麼特殊構造文法,便可用特定規則獲取相應內容。依賴的模塊是 re
首先從新觀察直接返回的內容中,須要的文字先後有什麼特殊:
import requests import re url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text print(response)
觀察幾個數目相信就有答案了:<div class="name"><a href="http://product.dangdang.com/xxxxxxxx.html" target="_blank" title="xxxxxxx"> 書名就藏在上面的字符串中,蘊含的網址連接中末尾的數字會隨着書名而改變。
分析到這裏正則表達式就能夠寫出來了:
import requests import re url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text def re_for_parse(response): reg = '<div class="name"><a href="http://product.dangdang.com/\d+.html" target="_blank" title="(.*?)">' for title in re.findall(reg, response): print(title) if __name__ == '__main__': re_for_parse(response)
能夠發現正則寫法是最簡單的,可是須要對於正則規則很是熟練。所謂正則大法好!
固然,不論哪一種方法都有它所適用的場景,在真實操做中咱們也須要在分析網頁結構來判斷如何高效的定位元素,最後附上本文介紹的四種方法的完整代碼,你們能夠自行操做一下來加深體會
import requests from bs4 import BeautifulSoup from lxml import html import re url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-24hours-0-0-1-1' response = requests.get(url).text def bs_for_parse(response): soup = BeautifulSoup(response, "lxml") li_list = soup.find('ul', class_='bang_list clearfix bang_list_mode').find_all('li') for li in li_list: title = li.find('div', class_='name').find('a')['title'] print(title) def css_for_parse(response): soup = BeautifulSoup(response, "lxml") li_list = soup.select('ul.bang_list.clearfix.bang_list_mode > li') for li in li_list: title = li.select('div.name > a')[0]['title'] print(title) def xpath_for_parse(response): selector = html.fromstring(response) books = selector.xpath("//ul[@class='bang_list clearfix bang_list_mode']/li") for book in books: title = book.xpath('div[@class="name"]/a/@title')[0] print(title) def re_for_parse(response): reg = '<div class="name"><a href="http://product.dangdang.com/\d+.html" target="_blank" title="(.*?)">' for title in re.findall(reg, response): print(title) if __name__ == '__main__': # bs_for_parse(response) # css_for_parse(response) # xpath_for_parse(response) re_for_parse(response)