BeautifulSoup庫用於從HTML或XML文件中提取數據。它可以自動將複雜的HTML文檔轉換為樹形結構,並提供簡單的方法來搜索文檔中的節點,使得我們可以輕鬆地遍歷和修改HTML文檔的內容。廣泛用於Web爬蟲和數據抽取應用程式中。 ...
BeautifulSoup庫用於從HTML或XML文件中提取數據。它可以自動將複雜的HTML文檔轉換為樹形結構,並提供簡單的方法來搜索文檔中的節點,使得我們可以輕鬆地遍歷和修改HTML文檔的內容。廣泛用於Web爬蟲和數據抽取應用程式中。
讀者如果需要使用這個庫,同樣需要執行pip命令用以安裝:
- 安裝PIP包:pip install bs4 -i https://pypi.tuna.tsinghua.edu.cn/simple
21.8.1 屬性定位鏈接
通過HTML
屬性我們可以輕鬆的實現對特定頁面特定元素的提取,如下代碼我們首先封裝兩個函數,其中get_page_attrs
函數用於一次性解析需求,函數search_page
則用於多次對頁面進行解析,這兩個函數如果傳入attribute
屬性則用於提取屬性內的參數,而傳入text
則用於提取屬性自身文本。
import requests
from bs4 import BeautifulSoup
header = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98"}
# 參數1: 解析頁面URL
# 參數2: 需要解析的頁面定位
# 參數3: 提取標簽屬性
# 參數4:設置超時時間
# 參數5:設置返回類型(attribute 返回屬性欄位,text 返迴文本欄位)
def get_page_attrs(url,regx,attrs,timeout,type):
respon_page = []
try:
respon = requests.get(url=url, headers=header, timeout=timeout)
if respon.status_code == 200:
if respon != None:
soup = BeautifulSoup(respon.text, "html.parser")
ret = soup.select(regx)
for item in ret:
if type == "attribute":
respon_page.append( str(item.attrs[attrs] ))
if type == "text":
respon_page.append(str(item.get_text()))
return respon_page
else:
return None
except Exception:
return None
return None
# 對頁面多次搜索
# 參數1: 需要解析的html文本
# 參數2: 需要解析的頁面定位
# 參數3: 提取標簽屬性
# 參數5:設置返回類型(attribute 返回屬性欄位,text 返迴文本欄位)
def search_page(data,regx,attrs,type):
respon_page = []
if data != None:
soup = BeautifulSoup(data, "html.parser")
ret = soup.select(regx)
for item in ret:
if type == "attribute":
respon_page.append( str(item.attrs[attrs] ))
if type == "text":
respon_page.append(str(item.get_text()))
return respon_page
通過使用上述兩個封裝函數,讀者就可以輕鬆的實現對特定網頁頁面元素的定位,首先我們通過CSS
屬性定位一篇文章中的圖片鏈接,這段代碼如下;
if __name__ == "__main__":
# 通過CSS屬性定點陣圖片
ref = get_page_attrs("https://www.cnblogs.com/LyShark/p/15914868.html",
"#cnblogs_post_body > p > img",
"src",
5,
"attribute"
)
print(ref)
當上述代碼運行後,即可提取出特定網址鏈接內,屬性#cnblogs_post_body > p > img
中圖片的src
屬性,並提取出圖片屬性attribute
自身參數。
接著我們繼續使用該函數實現定位文章列表功能,文章列表的定位同理,此處第二個參數應修改為href
屬性,如下代碼分別使用兩種方式實現對文章列表的定位功能;
if __name__ == "__main__":
# 定位文章列表,兩種方式均可
ref = get_page_attrs("https://www.cnblogs.com/lyshark",
"#mainContent > div > div > div.postTitle > a",
"href",
5,
"attribute"
)
print(ref)
ref = get_page_attrs("https://www.cnblogs.com/lyshark",
"div[class='day'] div[class='postCon'] div a",
"href",
5,
"attribute"
)
print(ref)
代碼運行後即可輸出lyshark
網站中主頁所有的文章地址信息,輸出如下圖所示;
當需要定位文章內容時,我們只需要將第二個屬性更改為空格,並將第四個屬性修改為text
此時則代表只提取屬性內的文本。
if __name__ == "__main__":
# 定位文章文本欄位
ref = get_page_attrs("https://www.cnblogs.com/lyshark",
"div[class='day'] div[class='postCon'] div[class='c_b_p_desc']",
"",
5,
"text"
)
for index in ref:
print(index)
運行上述代碼片段,即可提取出主頁中所有的文本信息,如下圖所示;
如果需要在同一個頁面中多次定位那麼就需要使用search_page
函數了,如下代碼中我們需要在一個頁面內尋找兩個元素,此時就需要定位兩次;
if __name__ == "__main__":
respon = requests.get(url="https://yiyuan.9939.com/yyk_47122/", headers=header, timeout=5)
ref = search_page(respon.text,
"body > div.hos_top > div > div.info > div.detail.word-break > h1 > a",
"",
"text"
)
print(ref)
ref = search_page(respon.text,
"body > div.hos_top > div > div.info > div.detail.word-break > div.tel > span",
"",
"text"
)
print(ref)
代碼運行後,即可通過依次請求,分別輸出該頁面中的兩個元素,如下圖所示;
21.8.2 查詢所有標簽
使用find_all
函數,可實現從HTML
或XML
文檔中查找所有符合指定標簽和屬性的元素,返回一個列表,該函數從用於精確過濾,可同時將該頁中符合條件的數據一次性全部篩選出來。
其基本語法為:
find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)
- name:標簽名或列表,用於查找指定標簽名的元素,如果為 True 或 None,則查找所有標簽元素
- attrs:字典,用於指定屬性名和屬性值,用於查找具有指定屬性名和屬性值的元素
- recursive:布爾值,表示是否遞歸查找子標簽,預設為 True
- text:字元串或正則表達式,用於匹配元素的文本內容
- limit:整數,限制返回的匹配元素的數量
- kwargs:可變參數,用於查找指定屬性名和屬性值的元素
我們以輸出CVE
漏洞列表為例,通過使用find_all
查詢頁面中所有的a
標簽,並返回一個列表,通過對列表元素的解析,依次輸出該漏洞的序號,網址,以及所對應的編號信息。
import re
import requests
from bs4 import BeautifulSoup
header = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98"}
# 查找文中 所有a標簽 且類名是c_b_p_desc_readmore的 並提取出其href欄位
# print(bs.find_all('a',class_='c_b_p_desc_readmore')[0]['href'])
# 提取 所有a標簽 且id等於blog_nav_admin 類等於menu 並提取出其href欄位
# print(bs.find_all('a',id='blog_nav_admin',class_='menu')[0]['href'])
# print(bs.find_all('a',id='blog_nav_admin',class_='menu')[0].attrs['href'])
if __name__ == "__main__":
url = "https://cassandra.cerias.purdue.edu/CVE_changes/today.html"
new_cve = []
ret = requests.get(url=url, headers=header, timeout=5)
soup = BeautifulSoup(ret.text, 'html.parser')
for index in soup.find_all('a'):
href = index.get('href')
text = index.get_text()
cve_number = re.findall("[0-9]{1,}-.*",index.get_text())
print("序號: {:20} 地址: {} CVE-{}".format(text,href,cve_number[0]))
讀者可自行運行上述代碼,即可匹配出當前頁面中所有的CVE
漏洞編號等,如下圖所示;
21.8.3 取字串返回列表
在BeautifulSoup4中,stripped_strings
是一個生成器對象,用於獲取HTML
標簽內所有文本內容的迭代器。它會自動去除每個文本的前後空格和換行符,只返回純文本字元串。stripped_strings
可以用於處理HTML
文檔中的多行文本、空格等特殊符號,也可用於將元素下麵的所有字元串以列表的形式返回。
import requests
from bs4 import BeautifulSoup
header = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98"}
if __name__ == "__main__":
ret = requests.get(url="https://www.cnblogs.com/lyshark", headers=header, timeout=3)
text = str(ret.content.decode('utf-8'))
bs = BeautifulSoup(text, "html.parser")
ret = bs.select('#mainContent > div > div > div.postTitle > a > span')
for i in ret:
# 提取出字元串並以列表的形式返回
string_ = list(i.stripped_strings)
print(string_)
運行後即可獲取選中元素的字元串內容,並通過list
將其轉換為列表格式,如下圖所示;
通過find_all
以及stripped_strings
屬性我們實現一個簡單的抓取天氣的代碼,以讓讀者可以更好的理解該屬性是如何被使用的,如下代碼所示;
from bs4 import BeautifulSoup
import requests
head = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
ret = requests.get(url="http://www.weather.com.cn/textFC/beijing.shtml", headers=head, timeout=3)
text = str(ret.content.decode('utf-8'))
bs = BeautifulSoup(text,"html.parser")
# 定位到第一個標簽上
bs.find_all('div',class_='conMidtab')[1]
# 在conMidtab裡面找tr標簽並從第3個標簽開始保存
tr = bs.find_all('tr')[2:]
for i in tr:
# 迴圈找代碼中的所有td標簽
td = i.find_all('td')
# 找所有的td標簽,並找出第一個td標簽
city_td = td[0]
# 獲取目標路徑下所有的子孫非標簽字元串,自動去掉空字元串
city = list(city_td.stripped_strings)[0]
# 取出度數的標簽
temp = td[-5]
temperature = list(temp.stripped_strings)[0]
print('城市:{} 溫度:{}'.format(city,temperature))
我們以提取北京天氣為案例,當運行代碼後即可取出北京市所有地區的氣溫數據,如下圖所示;
本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/ac89ee84.html
版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
版權聲明:本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!