DataWhale 组队学习爬虫 Task2
任務描述:
2.1 學習beautifulsoup
學習beautifulsoup,并使用beautifulsoup提取內容。
使用beautifulsoup提取丁香園論壇的回復內容。
丁香園直通點:http://www.dxy.cn/bbs/thread/626626#626626 。
參考資料:https://blog.csdn.net/wwq114/article/details/88085875
2.2學習xpath
學習xpath,使用lxml+xpath提取內容。
使用xpath提取丁香園論壇的回復內容。
丁香園直通點:http://www.dxy.cn/bbs/thread/626626#626626 。
參考資料:https://blog.csdn.net/naonao77/article/details/8812999
?
--------------------------------------------------這是不怎么華麗的分割線-------------------------------------------------
聲明一下:本文是為了學習爬蟲,因此以下的內容可能是跟著以上鏈接中的教程操作一遍,有與原文相同的部分,該部分的版權歸原作者所有。若有錯誤,請朋友指正。
?
1. 學習beautifulsoup
一、Beautifulsoup是一個包,將前面獲取到的html編碼變成一個樹狀的結構。 HTML頁面的代碼其實就是一個樹狀的結構:
最開始是<!DOCTYPE html>
并列往下<html lang="zh-cn">
在往下:<head></head>。 head之中就會開始有樹形的結構標簽,比如有<style><\style>,<meta><\meta>,然后style中又有其他。
head并列往下就會有<>body<\body>, body中有多個div,div中又有其他比如標簽,比如td,tr,a。
二、獲取到html的信息后,導入beautifulsoup包,使用find函數再去獲取需要的內容。
find函數用法:
find(name, attrs, recursive, text, **wargs) # recursive 遞歸的,循環的
這些參數相當于過濾器一樣可以進行篩選處理。不同的參數過濾可以應用到以下情況:
查找標簽,基于name參數
查找標簽的屬性,基于attrs參數
查找文本,基于text參數
基于正則表達式的查找
基于函數的查找
代碼實現:
使用urllib.request獲取html
from urllib import requesturl = 'http://www.dxy.cn/bbs/thread/626626' headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0'} req = request.Request(url=url, headers=headers) res = request.urlopen(req).read() print(res.decode('utf-8')) #打印時要轉碼with open('dxy.html', 'wb') as f:f.write(res) #寫入文件時,不要轉碼返回的打印內容及保存的dxy.html文件,文件大小69k。
注意:這里遇到一個問題,就是python中用print打印出來時,需要decode('utf-8'),保存成html文件時,不要轉碼,直接用read()的結果寫入。
使用beautifulsoup的find函數獲取標簽內容
從流浪器網頁f12后,可以看到用戶名在div class='auth'中(圖一),評論內容在td class='postbody'中(圖二),而每一段評論的所有內容都包含在一個tbody中,其實往上一層,是包含在一個div中(圖三)。
因此教程里面用一個findall,找到所有的tbody,其實用findall找div也可以,但比較浪費資源
找到所有的tbody后,就開始找具體的名字和評論內容,找不到則要跳過,因此用一個try功能實現。
圖一:?
圖二:?
圖三:?
代碼實現:
from bs4 import BeautifulSoup as bs html = bs(res,'lxml')datas = [] #用來獲取所有遍歷到的結果 for data in html.find_all("tbody"):try:username = data.find("div", class_="auth").get_text(strip=True)print(username)content = data.find('td', class_='postbody').get_text(strip=True)print(content)datas.append((username,content)) #內層的括號,將每一個結果的子結果組合起來except:pass # 找不到就pass,因為findall找到的tbody中,可能沒有對應的auth和postbody,上面tbody換成div也是可以的!print(datas)由以上代碼可以看到:
findall返回的結果是tboday的內容,findall返回的多個符合條件的結果,可以用一個for循環每一個結果,每一個結果又可以用find函數把對應的標簽內容找到。
返回的結果:
?
?
2. 學習xpath
Xpath - 用于確定XML文檔中某部分位置的語言。
XPath 中,有七種類型的節點:元素、屬性、文本、命名空間、處理指令、注釋以及文檔(根)節點。XML 文檔是被作為節點樹來對待的。
- XPath 用“/”來作為上下層級間的分隔,第一個“/”表示文檔的根節點<html></html>
- 定位某一個HTML標簽,可以用
絕對路徑:如 page_content.xpath(u"/html/body/p"),找到body下的所有p表情
??? 或
相對路徑:如 page_content.xpath(u"//p"),找到整個html中的所有p標簽 - 添加過濾條件:
page_content.xpath(u"//p[@style='font-size: 200%']")? # 標簽屬性中有style='font-size: 200%
page_content.xpath(u"//p[text() = 'hello']")?? #標簽的文本內容包含'hello'
page_content.xpath(u"//div/ul/li[position() = 2]") #所有div中ul的第二個li標簽,可簡化為...li[2]
數字定位和過濾條件的順序:
??? ul/li[5][@name='hello'] - ul第五個li,且name='hello',否則返回空
??? ul/li[@name='hello'][5] - ul下,第五個name為hello的標簽,否則返回空 -
通配符 * 可以代替所有的節點名,/html/body/*/span 代表body下的所有span標簽
-
descendant:: 代表任意多層的中間節點,可以省略成一個 /
/descendant::div[@id='leftmenu'] 或 //div[@id='leftmenu']? 所有id為leftmenu的div -
page.xpath(u"/descendant::*[text()]")
表示任意多層的中間節點(相同的節點)下任意標簽之間的內容,也即實現蜘蛛抓取頁面內容功能。 - 不同節點之間的內容獲取 (假如需要獲取"取不到的內容"這幾個字,該怎么做的?)
xpath(u"//div[tail='<br />']")??? # 失敗.....:(
xpath(u"/body/div[tail]")? ? # 失敗.....:( <div class="news">1. <b>無流量站點清理公告</b> 2013-02-22<br/>取不到的內容 </div> <div class="news"> 2. <strong>無流量站點清理公告</strong> 2013-02-22<br />取不到的內容 </div> <div class="news"> 3. <span>無流量站點清理公告</span> 2013-02-22<br />取不到的內容 </div> -
following-sibling:: 同一層的下一個節點
-
使用模塊 lxml.html.clean 的一個Cleaner 類來清理 HTML 頁
支持刪除嵌入或腳本內容、 特殊標記、 CSS 樣式注釋或者更多
??? cleaner = Cleaner(style=True, scripts=True,page_structure=False, safe_attrs_only=False)
??? # 注意,page_structure,safe_attrs_only為False時保證頁面的完整性,否則,這個Cleaner會把你的html結構與標簽里的屬性都給清理了。
??? print(cleaner.clean_html(html)) - 忽略大小寫可以:
page = etree.HTML(html)
keyword_tag = page.xpath("//meta[translate(@name,'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz')='keywords']")?
語法格式:
from lxml import etree:
html_document = ''' HTML 文檔 '''
tree = etree.HTML(html_document.lower().decode('utf-8'))?? # 需要用utf-8解碼
elements = page_content.xpath(u"//標簽")?? # 根目錄下的所有a標簽元素
for element in elements :
??? print(element.attrib) ?? # 打印標簽的屬性
??? print(element.text) ?? # 打印標簽的內容
使用lxml前注意事項:先確保html經過了utf-8解碼,即code = html.decode('utf-8', 'ignore'),否則會出現解析出錯情況。因為中文被編碼成utf-8之后變成 '/u2541' 之類的形式,lxml一遇到 “/”就會認為其標簽結束。
參考別人的例子:
html_document=''' <html><head><meta name="content-type" content="text/html; charset=utf-8" /><title>友情鏈接查詢 - 站長工具</title><!-- uRj0Ak8VLEPhjWhg3m9z4EjXJwc --><meta name="Keywords" content="友情鏈接查詢" /><meta name="Description" content="友情鏈接查詢" /></head><body><h1 class="heading">Top News</h1><p style="font-size: 200%">World News only on this page</p>Ah, and here's some more text, by the way.<p>... and this is a parsed fragment ...</p><a href="http://www.cydf.org.cn/" rel="nofollow" target="_blank">青少年發展基金會</a><a href="http://www.4399.com/flash/32979.htm" target="_blank">洛克王國</a><a href="http://www.4399.com/flash/35538.htm" target="_blank">奧拉星</a><a href="http://game.3533.com/game/" target="_blank">手機游戲</a><a href="http://game.3533.com/tupian/" target="_blank">手機壁紙</a><a href="http://www.4399.com/" target="_blank">4399小游戲</a><a href="http://www.91wan.com/" target="_blank">91wan游戲</a></body> </html> '''from lxml import etree tree= etree.HTML(html_document.lower()) # page_content = etree.HTML(html_document.lower().decode('utf-8)) # 這里使用decode('utf-8')出錯了,string類型只有encode()屬性? # 或許是因為文本已經是解碼過的 # 嘗試改為page_content = etree.HTML(html_document.lower().encode('utf-8)), # 反而沒報錯但出現亂碼 elements = tree.xpath(u"//a") for element in elements:print(element.attrib) #打印出來是字典類型print(element.text) #打印出來是文本類型print('--'*20)返回:
注意:
page_content = etree.HTML(html_document.lower().decode('utf-8)),這里面的decode需要根據前面的對象使用,上面舉的例子用文本,文本沒有decode('utf-8)的屬性.....
element.attrib 結果是字典類
element.text 結果是文本
參考:https://www.cnblogs.com/descusr/archive/2012/06/20/2557075.html
?
Xpath 案例
參考https://blog.csdn.net/naonao77/article/details/88129994
待補充。。。。
?
?
?
?
?
?
?
?
?
--- End ---
總結
以上是生活随笔為你收集整理的DataWhale 组队学习爬虫 Task2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot 0709
- 下一篇: Rsync服务