我爬自己or我自己爬——記錄在B站專欄上的一次Python爬蟲應用
一、問題描述
? ? 獲取我自己寫的n篇UnderMine專欄中的166件圣物數據,將它們的效果、簡評、評分按編號順序錄入已有的excel表格中,作為UM圣物查詢軟件的數據庫。其中效果和簡評需要保留html代碼并修改成軟件可渲染的html格式。

關鍵詞:python? 爬蟲/web?crawler? BeautifulSoup4

二、思路分析
2.1?獲取專欄中的166件圣物數據
方法一:最樸素的思想——復制粘貼
如果這個方法能簡單解決問題,我也不會寫這篇專欄了......
首先,很遺憾,直接復制粘貼并不能達到我期望的效果。因為我想要html代碼的數據,這樣在查詢軟件中也能渲染出加粗、顏色等文字效果。如果用F12+復制指定元素,需要我手動執(zhí)行166*3次,人都點麻了。
其次,專欄內容的圣物不是完全按編號升序排列的,需要手動填入表格的對應編號行,費眼睛??梢暂斎雴卧裉杹砜焖俣ㄎ?,但還是好麻煩。
方法二:網絡爬蟲
網絡爬蟲,是一種按照既定規(guī)則自動抓取網絡數據或執(zhí)行網絡請求的程序,比較適合完成此類任務。之前淺學過一段時間,現(xiàn)在拿出來實際運用一下。
選用的策略是:獲取html文檔,喂給BeautifulSoup4(簡稱bs4)來解析,然后抽出想要的信息。重點就在于如何抽取所需信息——需要找出這些信息的特征,才能讓bs4定位到信息所在標簽tag,取出內容。

2.1.1 獲取html文檔
我所要的信息分布在10篇專欄中,訪問它們的關鍵就在于CV號。

還好我有做過一篇目錄專欄,通過它可以很方便地獲?。ㄅ繿標簽)到這些CV號。

使用requests庫向發(fā)送html get請求后,10篇專欄的HTML文檔就到手了!

2.1.2?使用bs4來解析html文檔
Beautiful Soup是一個可以從HTML或XML文件中提取數據的Python庫,它能夠通過你喜歡的轉換器實現(xiàn)慣用的文檔導航,查找,修改文檔的方式。
——BS4官方文檔

接下來是為之后bs4定位“效果”“簡評”“評分”tag做準備,先使用瀏覽器的“檢查(inspect)”功能來查看各圣物專欄的tag特征。

首先,在檢查后發(fā)現(xiàn),專欄的內容部分在id=read-article-holder的div標簽中,初步縮小了搜索范圍。

其次,可以發(fā)現(xiàn)在div標簽下含了無數的沒有id的同級p標簽。
由上圖可見,編號,簡評,評分都在p標簽里,而周圍都是同級的p標簽,所以無法通過標簽名、只能以標簽內容來定位。
效果的內容都在ul列表標簽內,專欄內使用此標簽的也只有效果部分,可以作為標志來定位。

2.1.3 抽取信息
獲取編號
只需要保留數字。對p標簽內容使用正則表達式取數字或者用字符串split函數取第二段
獲取效果
需要保留html代碼。獲取整個ul標簽后使其變?yōu)樽址鎯?/p>
獲取簡評
需要保留html代碼。從簡評標簽之后到評分標簽之前,獲取連續(xù)的n個p標簽后使其變?yōu)樽址鎯?/p>
獲取評分
需要保留普通字符串。獲取去除“評分”和“空字符”后p標簽內容。

2.2?效果、簡評、評分按序錄入已有excel

根據表頭,定位效果、評論和分數列號。
如果是xls文件需要xlrd、xlwt庫進行讀寫、xlutils庫允許在原表格上追加修改
如果是xlsx文件只需要openpyxl庫即可完成讀寫和修改
根據編號,定位行號。按行列定位單元格,依次輸入對應圣物的效果、簡評、評分內容

三、代碼實現(xiàn)
2.0.0 導入包和模塊

2.1.1 獲取html文檔

2.1.2?使用bs4來解析html文檔

2.1.3~2.2?抽取信息+效果、簡評、評分按序錄入已有excel

2.3 測試代碼

四、結果展示






五、實驗反思
5.1 代碼改進
以上代碼似乎缺少了些面向對象的思想,這組功能圍繞CV號、HTML文件和BS結構樹展開,顯然可以編成類,以進一步簡化代碼:
測試代碼:

5.2 未來可能的改進
設置私有、只讀屬性/方法,保證數據安全。
增加容錯處理,如HTML文檔爬取失敗的情況,調用后續(xù)函數需要檢查是否初始化成功。
改進篩選函數,部分find_all可能多爬/少爬某些格式的信息,隨著未來專欄的增多,可能會出現(xiàn)不可預期的錯誤,需要定期檢查以及設置一些查看爬取信息的方法。

5.3 已解決的疑問
一開始,我的評分過濾器是從解析順序著手的,用了BS遍歷文檔樹-回退和前進的.next/previous_element方法:
但對第一篇專欄的提取數據卻不符合預期:

于是我嘗試查看這些無關標簽滿足篩選條件的原因:

問題得以迎刃而解:
字符串的find方法結果出現(xiàn)了None!而不是-1,所以通過了檢測。原因是解析的結果不一定是字符串也有可能是tag,find方法接收到了非str類型的數據,返回了None
"評分標準"字符串的開頭的確是評分二字,但不含有圣物信息,所以需要額外增加篩選條件,把此類信息濾掉

后來又改用get_text方法獲取tag中包含的所有文本內容,還能去除tag間多余的空格,好用!

六、筆記總結
6.1 BeautifulSoup常用方法總結
6.1.1 篩選出指定條件的tag
find_all()方法
功能:搜索當前tag的所有子孫節(jié)點,并篩選出所有符合條件的tag,返回值為列表
語法:tag或BeautifulSoup對象.find_all(name, attrs, recursive, string, **kwargs)
簡寫:可以省略掉.find_all
參數:
name,表示tag名稱,可以是字符串/正則表達式/列表/方法/True
attrs,表示特殊屬性的tag,字典類型(本文沒用到)
recursive,表示是否檢索當前tag的所有子孫節(jié)點,布爾類型,默認為True,F(xiàn)alse表示只搜索tag的直接子節(jié)點
string,表示搜索字符串內容,可以是字符串/正則表達式/列表/方法/True
**kwargs,表示一堆關鍵字參數。其中,limit表示返回結果的最大數量,int類型;class_表示按照CSS類名搜索tag,可以是過濾器/字符串/正則表達式/方法/True;其他參數名表示搜索指定名字的屬性,可以是字符串/正則表達式/列表/True
相似方法:find()方法,是find_all()方法的單數版本,有相同的形參,返回首個符合條件的tag
find_previous()方法
功能:搜索當前節(jié)點前符合條件的首個tag或字符串
語法:tag.find_previous(name, attrs, recursive, string, **kwargs)
參數:參考find_all()方法
相似方法:find_all_previous()方法,是find_previous()方法的復數版本,返回當前節(jié)點前所有符合條件的tag或字符串;而find_next(),find_all_next()是搜索當前節(jié)點后。它們都有相同的形參。
find_next_sibling()方法
功能:搜索當前節(jié)點后的所有兄弟節(jié)點,返回首個符合條件的tag
語法:tag或BeautifulSoup.find_next_sibling(name,?attrs,?recursive,?string,?**kwargs)
參數:參考find_all()方法
相似方法:find_next_siblings()方法,是find_next_sibling()方法的復數版本;而find_previous_sibling(),find_previous_siblings()是搜索當前節(jié)點前。它們都有相同的形參。

6.1.2 得到tag內的字符串
string方法
功能:對于僅含一段文本的tag或只有一個子標簽且文本只出現(xiàn)在子標簽間的tag,返回這段文本字符串
語法:tag.string
注意:tag包含多個子節(jié)點時,tag.string無法確定調用哪個子節(jié)點的內容,返回None
相似方法:strings方法,對于包含多個文本字符串的tag,返回一個包含所有文本字符串的生成器,可以使用for循環(huán)來獲取其中的內容;stripped_strings方法,是去除空格、空行的strings版本。它們都不需要形參。
get_text()方法
功能:獲取tag所含所有文本內容,包括子孫tag中的內容,返回合并后的Unicode字符串
語法:tag或BeautifulSoup對象.get_text(sep, strip=True)
參數:
sep表示相鄰文本內容的分隔符,str類型
strip表示是否去除文本內容前后的空白符,布爾類型,True則去除

七、參考資料
1. BS4官方說明文檔-中文版
https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/
2. xlsx文件的讀寫(openpyxl庫的使用)
https://blog.csdn.net/liuyingying0418/article/details/101066630
3. xls文件的讀寫(xlrd/xlwt/xlutils庫的使用)
https://cooc.cqmu.edu.cn/Course/KnowledgePoint/9389.aspx
4. 正則表達式的用法(re模塊的使用)
https://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html
5. BS4中string和text的區(qū)別
https://www.cnblogs.com/kaibindirver/p/11374669.html