日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup...

發(fā)布時間:2023/12/19 编程问答 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://www.cnblogs.com/binye-typing/p/6656595.html

  讀者可能會奇怪我標(biāo)題怎么理成這個鬼樣子,主要是單單寫 lxml 與 bs4 這兩個 py 模塊名可能并不能一下引起大眾的注意,一般講到網(wǎng)頁解析技術(shù),提到的關(guān)鍵詞更多的是 BeautifulSoup 和 xpath ,而它們各自所在的模塊(python 中是叫做模塊,但其他平臺下更多地是稱作庫),很少被拿到明面上來談?wù)摗O旅嫖覍男省?fù)雜度等多個角度來對比 xpath 與 beautifulsoup 的區(qū)別。

效率

從效率上來講,xpath 確實(shí)比?BeautifulSoup?高效得多,每次分步調(diào)試時,soup?對象的生成有很明顯的延遲,而?lxml.etree.HTML(html) 方式則在?step?over?的一瞬間便構(gòu)建成功了一個可執(zhí)行?xpath?操作的對象,速度驚人。原理上來講,bs4 是用 python 寫的,lxml 是 c 語言實(shí)現(xiàn)的,而且 BeautifulSoup 是基于 DOM 的,會載入整個文檔,解析整個DOM樹,因此時間和內(nèi)存開銷都會大很多。而lxml只會進(jìn)行局部遍歷。

使用復(fù)雜度

從使用復(fù)雜度來講,beautifulsoup?的?find?方法要比?xpath?簡單,后者不僅要求通曉?xpath?語法,而且?xpath?方法的返回對象始終是一個?list,這使得對于頁面中一些唯一元素的處理有些尷尬,比如根據(jù)?id?獲取頁面某一標(biāo)簽,下面我用兩種方式實(shí)現(xiàn)一個獲取網(wǎng)頁導(dǎo)航欄的方法 (注釋部分為 bs4 的實(shí)現(xiàn)): 1 def get_nav(self,response): 2 # soup = BeautifulSoup(response.body_as_unicode(), 'lxml') 3 # nav_list = soup.find('ul', id='nav').find_all('li') 4 model = etree.HTML(response.body_as_unicode()) 5 nav_list = model.xpath('//ul[@id="nav"]/li') 6 for nav in nav_list[1:]: 7 # href = nav.find('a').get('href') 8 href = nav.xpath('./a/@href')[0] 9 yield Request(href, callback=self.get_url)

?

  可以看到 xpath 除了其特殊的語法看上去有些別扭(跟正則表達(dá)式似的)以外,它在代碼簡潔度上還是可觀的,只是所有 xpath 方法的返回結(jié)果都是一個 list ,如果匹配目標(biāo)是單個元素,對于無腦下標(biāo)取0的操作,強(qiáng)迫癥患者可能有些難受。相比之下,BeautifulSoup 這一長串的 find 與 find_all 方法顯得有些呆板,如果碰到搜索路線比較曲折的,比如:

# href = article.find('div', class_='txt').find('p', class_='tit blue').find('span').find('em').find('a').get('href') href = article.xpath('./div[@class="txt"]//p[@class="tit blue"]/span/em/a/@href')[0]

?

  這種情況下,BeautifulSoup 的寫法就顯得有些讓人反胃了,當(dāng)然一般情況下不會出現(xiàn)這么長的路徑定位。

?

功能缺陷總結(jié)——BeautifulSoup

   BeautifulSoup 在使用上的一個短板,就是在嵌套列表中去匹配元素的時候會顯得很無力,下面是一個例子(具體網(wǎng)頁結(jié)構(gòu)可根據(jù) index_page 在瀏覽器打開進(jìn)行審查):

1 class RankSpider(spider): 2 name = 'PCauto_rank' 3 index_page = 'http://price.pcauto.com.cn/top/hot/s1-t1.html' 4 api_url = 'http://price.pcauto.com.cn%s' 5 6 def start_requests(self): 7 yield Request(self.index_page, callback=self.get_left_nav) 8 9 # 測試 BeautifulSoup 是否能連續(xù)使用兩個 find_all 方法 10 def get_left_nav(self,response): 11 # model = etree.HTML(response.body_as_unicode()) 12 # nav_list = model.xpath('//div[@id="leftNav"]/ul[@class="pb200"]/li//a[@class="dd "]') 13 soup = BeautifulSoup(response.body_as_unicode(), 'lxml') 14 nav_list = soup.find('div', id='leftNav').find('ul', class_='pb200').find_all('li').find_all('a', class_='dd') 15 for sub_nav in nav_list: 16 href = self.api_url % sub_nav.xpath('./@href')[0] 17 yield Request(href, callback=self.get_url) 18 19 def get_url(self): 20 pass

?

?

   使用注釋部分的 xpath 寫法沒什么問題,可實(shí)現(xiàn)準(zhǔn)確定位,但用到 BeautifulSoup 去實(shí)現(xiàn)相應(yīng)邏輯的時候,就要連續(xù)使用兩個 find_all 方法 ,顯然這種寫法不符合規(guī)范,運(yùn)行的時候會報(bào)?AttributeError: 'ResultSet' object has no attribute 'find_all' 錯誤,這時候我們要實(shí)現(xiàn)這種匹配,只能先去遍歷各個 li ,然后調(diào) find_all 方法找到 li 下的各個 a 標(biāo)簽,實(shí)在繁瑣,所以這種場景用 xpath 來解決會省下不少麻煩。

  當(dāng)然這里我只是單單為了詮釋這么個問題才在故意在拿目標(biāo) url 時分這么多級的,實(shí)際開發(fā)中我這里用的是:

1 # nav_list = model.xpath('//div[@id="leftNav"]///a[@class="dd "]') 2 nav_list = soup.find('div', id='leftNav').find_all('a', class_='dd')

?

  但如果說我們的目標(biāo)不是所有的 li 下面的 a 標(biāo)簽,而是部分 class="*" 的 li 下面的 a 標(biāo)簽,這時候我們就只能選擇使用 xpath 來達(dá)到目的,當(dāng)然如果你喜歡寫遍歷,覺得這樣寫出來邏輯展示更清晰,那你可以跳過這一節(jié)。

?

功能缺陷總結(jié)——xpath

xpath?的類選擇器在做公共類名選擇時有短板,也勉強(qiáng)把它算作功能缺陷吧,比如:      1 model = etree.HTML(response.body_as_unicode()) 2 model.xpath('//div[@class="box box-2 box-4"]') 無法定位?html?中 class?為?box?box-2?box-4?mt25?與?box?box-2?box-4?mt17?的兩個?div,必須分別以:? model.xpath('//div[@class="box box-2 box-4 mt25"]') model.xpath('//div[@class="box box-2 box-4 mt17"]')

?

  來匹配目標(biāo),這可能要?dú)w結(jié)于 xpath 在設(shè)計(jì)的時候本身就是以類名的完全匹配來確定目標(biāo)的,哪怕多一個空格:

頁面中一個?a?標(biāo)簽是這樣寫的:??<a?href="/top/hot/s1-t1.html"?class="dd?">5萬以下</a>?用?xpath?去選擇,寫作:

      model.xpath('//a[@class="dd"]')

死活匹配不到(當(dāng)時真的是蠻懵逼的),必須要在后面加空格,但在通過?js?控制臺?a.dd?這個類選擇器又可以定位到目標(biāo),而且 BeautifulSoup 調(diào) find_all('a', class_='dd') 也是沒有問題的,這種應(yīng)用場景下的 xpath 就略顯死板。

?

文本獲取

  xpath 目標(biāo)結(jié)點(diǎn)的 text 屬性值對應(yīng)的只是當(dāng)前匹配元素下面的文本信息,如要獲取該結(jié)點(diǎn)下面包括子結(jié)點(diǎn)在內(nèi)的所有文本內(nèi)容要使用 .xpath('string()') 的方式:

1   model = etree.HTML(response.body_as_unicode()) 2 place = model.xpath('//div[@class="guide"]') 3 # nav and aiticle 4 if place: 5 mark = place[0].xpath('./span[@class="mark"]') 6 if mark: 7 # text = mark[0].text.strip().replace('\n','').replace('\r','') # false 8 text = mark[0].xpath('string()') 9 result['address'] = text

?

?

其他方面比較

從參考資料上來講,bs4?有詳細(xì)中/英文版官方幫助文檔,lxml?好像?document?相對少。另外?BeautifulSoup 的結(jié)點(diǎn)對象在?Debugger?下面對于變量內(nèi)容的監(jiān)視更友好,它直接顯示匹配的?html?字符串,而?lxml?就是一個類似這種表示的對象:?<Element?html?at?0x####>,不是很友好,但這都不重要,筆者還是更喜歡 xpath 的高效,簡潔,一步到位。    ?

轉(zhuǎn)載于:https://www.cnblogs.com/mapu/p/8337407.html

總結(jié)

以上是生活随笔為你收集整理的关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。