您的位置:首頁>科技>正文

Python個性化主題網路爬蟲探究

21世紀以來, 在互聯網高速發展的背景下, 互聯網上的資訊呈現暴發式的增加, 對應的提供人們檢索資訊功能的搜尋引擎也在飛速發展、更新和反覆運算。

但現有的知名搜尋引擎能夠觸及的互聯網內容用九牛一毛來形容也毫不為過。 為了給細分領域的客戶提供更優質的搜索體驗, 建立一套自己的搜尋引擎就十分重要了。 建立一個搜尋引擎一般來說需要做這樣幾件事:

1、利用網路爬蟲自動下載網路頁面;

2、對爬取結果建立高效快速的索引;

3、根據相關性對網路進行準確的排序。

目前的爬蟲技術一般分為兩種:通用網路爬蟲和主題網路爬蟲。

通用網路爬蟲一般盡可能多的採集頁面, 而一般不關心被採集頁面的順序與頁面主題的相關性。 Google和百度等公司均採用通用網路爬蟲。

主題網路爬蟲則根據一個已經預定好的主題進行爬取採集, 最終對採集結果進行匯總, 其爬取頁面具有大量相關性。 相對通用網路爬蟲, 主題網路爬蟲所消耗的資源和網路頻寬更少, 所採集的主題相關性更強, 頁面的利用率更高。

本期“安仔課堂”, ISEC實驗室的葉老師為大家詳細剖析下主題網路爬蟲的幾個主要技術點。

一、遍歷演算法

1738年, 瑞典數學家歐拉( Leornhard Euler)解決了柯尼斯堡問題, 由此, 圖論誕生, 歐拉也成為了圖論的創始人。 圖由一些節點與連接這些節點的弧組成。

我們可以把互聯網看成一張具有指向無數方向的浩瀚無邊的圖, 每一張網頁為圖的一個節點, 每個網頁中的超連結為圖中的弧。 有了超連結, 我們可以從任何一個網頁出發, 用圖的遍歷演算法, 自動訪問到每一個頁面, 然後存儲所需要的資訊。

圖的遍歷演算法可以分為深度優先搜索(Depth-First Search 簡稱DFS)和廣度優先搜索(Breadth–First Search 簡稱BFS)。

由於深度優先搜索的遍歷方式, 在很多情況下會導致爬蟲在深度上過“深”地遍歷或者陷入黑洞, 大多數爬蟲不採用深度優先搜索, 目前主題爬蟲比較常見的是廣度優先搜索方式。

廣度優先搜索遍歷URL策略的基本思路是:將新下載網頁中發現的連結直接插入待抓取URL佇列的末尾。

也就是指網路爬蟲會先抓取起始網頁中連結的所有網頁, 然後再選擇其中的一個連結網頁, 繼續抓取在此網頁中連結的所有網頁。

圖1

如圖1, 廣度優先遍歷搜索(BFS)的訪問順序為:A->B->C->D->E->F->H->G->I 深度優先搜索策略從起始網頁開始, 選擇一個URL進入, 分析這個網頁中的URL,

選擇其中一個再進入。 如此一個連結接著一個連結地抓取下去, 一路走到黑, 直到處理完一條路線之後再處理下一條路線。 如圖1, 深度優先遍歷(DFS)的訪問順序為:A->B C D E->H->I F->G

不管是哪種方式, 理論上都可以保證訪問到所有的節點。 但是工程上基於穩定性等要求一般採用的都是BFS方式。

二、網路爬蟲

本文使用Python語言作為主開發語言。 在Python中使用urllib.urlopen(url[, data[, proxies]]) :創建一個表示遠端url的類檔物件, 然後像本地檔一樣操作這個類檔物件來獲取遠端資料。

Python可以使用urllib請求頁面獲取網頁HTML資訊, 實現如下:

from urllib.request import urlopen

html = urlopen(‘ www.baidu.com’)

得到原始程式碼後即可使用Xpath或者BeautifulSoup4解析HTML元素, 提取所需要資料。 以上, 即完成一個簡單的Web資料獲取流程。

但是具體的業務工程往往不是一個簡單的流程而已,

有時候會採集非結構化資料, 需要再由工程人員寫下載器, 進行非結構化資料的提取;有時候結構化資料是非同步載入, 需要我們類比載入的JavaScript代碼, 再對伺服器進行一次請求;對於需要代理才能訪問的網站, 需要再添加代理IP;還有採集的效率等等一系列問題。

三、HTTP請求頭的設計

流覽器與伺服器交互是基於超文字傳輸協定(HTTP, HyperText Transfer Protocol), HTTP是互聯網上應用最為廣泛的一種網路通訊協定。 HTTP是一個基於TCP/IP通信協定來傳遞資料(HTML 檔, 圖片檔, 查詢結果等)。

在爬取網站內容時, HTTP協定中請求頭的類比至關重要, 請求頭不正確將會導致目標網站返回錯誤的狀態碼和無效的字元;例如在對某同城租房模組的資料獲取中, 先是使用chrome流覽器請求租房頁面, 查找到流覽器請求目標網站的資料包,分析請求頭,然後模擬了一個類似的請求頭,代碼如下:

headers = [

{

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',

}, # 請求頭1

{

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2',

}, # 請求頭2

]

header = random.choice(headers) # 隨機選取請求頭

其中 'Connection': 'keep-alive', 建議保持打開狀態。

我們知道HTTP協議採用“請求-應答”模式,當使用普通模式,即非KeepAlive模式時,每個請求—應答用戶端和伺服器都要新建一個連接,完成之後立即斷開連接(HTTP協定為不需連線的協定);當使用Keep-Alive模式(又稱持久連接、連接重用)時,Keep-Alive功能使用戶端到伺服器端的連接持續有效,當出現對伺服器的後繼請求時,Keep-Alive功能避免了建立或者重新建立連接。

http1.0協定中預設是關閉的,需要在http頭加入"Connection: Keep-Alive",才能啟用Keep-Alive;http1.1協議中預設啟用Keep-Alive,如果加入"Connection: close ",才關閉。目前大部分流覽器都是用http1.1協定,也就是說預設都會發起Keep-Alive的連接請求了,所以是否能完成一個完整的Keep- Alive連接就看伺服器設置情況。

從上面的分析來看,啟用Keep-Alive模式肯定更高效,性能更高。因為避免了建立及釋放連接的開銷。

以上兩個HTTP請求頭分別來自不同的流覽器,用這種方式請求,在一定概率上,每次請求都會讓伺服器以為是來自不同的流覽器發出的,使得伺服器會返回完整的HTML頁面給爬蟲端,爬蟲端就可以做出相應的解析,若是返回錯誤頁面、存在頁面、或者直接返回一串爬蟲無法解析的無效資訊,那麼提取資料從何談起。使用測試請求頭對爬取資料進行請求測試,若連接爬取多個頁面均無出現明顯錯誤,即可進入正式爬取階段。

但是使用類比請求頭的方式對於非同步Ajax載入的資料不好直接定位採集,需要對非同步Ajax載入的位置進行請求的重新類比,要先分析非同步請求,再類比載入請求再請求一次伺服器,對於爬蟲系統來說是很消耗性能的。所以,一般如果採集多種非同步資料,可以採用自動化測試工具Selenium模擬流覽器。

Selenium 是什麼?一句話,自動化測試工具。它支持各種流覽器,包括 Chrome,Safari,Firefox 等主流介面式流覽器,如果你在這些流覽器裡面安裝一個 Selenium 的外掛程式,那麼便可以方便地實現Web介面的測試;安裝一下 Python 的 Selenium 庫,再安裝好 PhantomJS,就可以實現 Python+Selenium+PhantomJS 的一整套體系的連接了!PhantomJS 用來渲染解析JavaScirpy,Selenium 用來驅動以及與 Python 的對接,Python 進行後期的處理。

利用Selenium模擬的流覽器能夠更加逼真模擬真實Web請求環境,對於Ajax非同步載入的資料可以快速定位。

但是在進行模擬爬取時,若觸發網站的防爬機制,那麼就必須進行多IP的模擬和對爬取執行緒採取暫時暫停,兩者相結合的辦法來測試防爬機制的臨界點,對於多IP的模擬可以採取二分折半測試的辦法,先取一個比較長的暫停時間。然後如果能使程式正常進行就再縮短一倍時間,否則擴大一倍時間,直到有一個臨近的值或者區間,再對該臨界值或者區間取亂數暫停爬取執行緒。

具體請求代碼如下:

def get_soup (url) :

logger.info('Prepare analytical this URL:')

logger.info(url)

print('準備解析該連結:', url)

# dis = { url : url }

# print(dis)

try:

try:

# 偽裝成流覽器

headers = [{

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',

}, {

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2',

}, {

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17',

},

]

header = random.choice(headers)

# 使用代理IP

proxy_ips = [

{'': '117.90.3.226:9000'},

{'': '210.136.19.75:8080'},

{'': '118.186.219.164:8080'},

{'': '121.232.147.177:9000'},

{'': '117.90.5.48:9000'},

{'': '138.186.84.129:8080'},

{'': '125.81.105.134:8998'},

{'': '114.253.210.125:8118'},

{'': '60.160.128.10:9999'},

]

proxy_ip = random.choice(proxy_ips)

proxy_support = urllib.request.ProxyHandler(proxy_ip)

opener = urllib.request.build_opener(proxy_support)

urllib.request.install_opener(opener)

# 請求

sleep(0.2)

request = Request(url=url, headers=header)

sleep(0.3)

response = urlopen(request)

except (HTTPError, URLError) as e:

logger.error('URL Error or HTTPError:')

logger.error(e)

print("請求有問題", e)

return None

try:

the_page = response.read()

soup = BeautifulSoup(the_page, "html.parser")

# 判斷是否有驗證碼 (得到所有soup的title)

title_value = soup.title.string.encode('utf-8')

# 驗證碼頁面的title.encode('utf-8')

verification_code = "請輸入驗證碼".encode('utf-8')

# (出現驗證碼了){阻塞或者暫停6666秒}

if title_value == verification_code:

logger.warning('Boom.........verification_code now!!!!!!!!!!!!!!!!!!!!!!!!!!!')

logger.warning('sleeping.......')

sleep(2222)

# name = input("The bomb is about to explode,Please input your name: ")

# print("Hello,", name)

# logger.warning('The bomb is about to explode')

# logger.warning(name)

soup = get_soup(url)

logger.warning('(warning)Revisit the link:')

logger.warning(url)

return soup

except AttributeError as e:

logger.error('AttributeError(Request soup)')

logger.error(e)

return None

return soup

except Exception as e:

logger.error('another Exception(Request soup)')

logger.error(e)

return None

四、HTML網頁的解析

爬蟲請求成功後,返回Soup,即HTML的原始程式碼。

HTML頁面中包含著大量的文本、連結、圖片等資訊,所有的HTML都以,開始結束。所有的HTML原始程式碼中均包含著大量的如等標籤,眾多標籤構成了完整的HTML文檔。DOM全稱 Document Object Model,即文檔物件模型。將文檔抽象成一個樹型結構,文檔中的標籤、標籤屬性或標籤內容可以表示為樹上的結點。

HTML文檔轉換為HTML DOM節點樹如圖2所示:

圖2

使用BeautifulSoup解析這段代碼,能夠得到一個 BeautifulSoup 的物件,並能按照標準的縮進格式的結構輸出:

from bs4 import BeautifulSoup

soup = BeautifulSoup(html_doc)

print(soup.prettify())

anscstory

anscstory

幾個簡單的流覽結構化資料的方法:

☛Soup.title 輸出內容: ansc story

☛soup.title.name輸出內容: u'title'

☛soup.title.string輸出內容:u' ansc story '

將一段文檔傳入BeautifulSoup的構造方法,就能得到一個文檔的物件, 可以傳入一段字串或一個檔案控制代碼。

在Beautiful Soup中最常用的函數為find_all()和find()。

find_all() 方法搜索當前tag的所有tag子節點,並判斷是否符合篩檢程式的條件

find_all( name , attrs , recursive , text , **kwargs )

name 參數

name參數可以查找所有名字為name的tag,字串物件會被自動忽略掉。搜索 name參數的值可以是任一類型的篩檢程式。

keyword 參數

如果一個指定名字的參數不是搜索內置的參數名,搜索時會把該參數當作指定名字tag的屬性來搜索,如果包含一個名字為id的參數,Beautiful Soup會搜索每個tag的“id”屬性。

按CSS搜索

按照CSS類名搜索tag的功能非常實用,但標識CSS類名的關鍵字 class 在Python中是保留字,使用class做參數會導致語法錯誤。從Beautiful Soup的4.1.1版本開始,可以通過 class_ 參數搜索有指定CSS類名的tag。

text 參數

通過text參數可以搜素文檔中的字串內容,與 name 參數的可選值一樣,text 參數接受字串、規則運算式、清單、True。

limit 參數

find_all() 方法返回全部的搜索結構,如果文檔樹很大那麼搜索會很慢。如果我們不需要全部結果,可以使用limit參數限制返回結果的數量。效果與SQL中的limit關鍵字類似,當搜索到的結果數量達到limit的限制時,就停止搜索返回結果。

find(name,attrs,recursive,text,**kwargs)

find_all() 方法將返回文檔中符合條件的所有tag,儘管有時候我們只想得到一個結果。比如文檔中只有一個標籤,那麼使用 find_all() 方法來查找標籤就不太合適,使用 find_all 方法並設置 limit=1 參數不如直接使用 find() 方法。

Beautiful Soup將複雜HTML文檔轉換成一個複雜的樹形結構,每個節點都是一個Python物件,所有物件都可以歸為4個種類:Tag ,NavigableString ,BeautifulSoup , Comment 。所以在解析HTML時,即是在操作Beautiful Soup裡頭的一個個Python物件。Beautiful Soup提供了強大的函式程式庫,所以任何HTML(或XML)檔的任意節點資訊,都可以被提取出來,只要目標資訊的旁邊或附近有標記即可。

資料經過清洗過濾之後提取出來,寫入文字檔或者持久化到MySQL。對於已經持久化到MySQL的資料,一方面可以進一步對該主題資料進行資料採擷,另一方面可以利用Java強大的Web處理能力展示資料,利用純Javascript圖表庫ECharts, 進行資料的視覺化展示。

查找到流覽器請求目標網站的資料包,分析請求頭,然後模擬了一個類似的請求頭,代碼如下:

headers = [

{

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',

}, # 請求頭1

{

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2',

}, # 請求頭2

]

header = random.choice(headers) # 隨機選取請求頭

其中 'Connection': 'keep-alive', 建議保持打開狀態。

我們知道HTTP協議採用“請求-應答”模式,當使用普通模式,即非KeepAlive模式時,每個請求—應答用戶端和伺服器都要新建一個連接,完成之後立即斷開連接(HTTP協定為不需連線的協定);當使用Keep-Alive模式(又稱持久連接、連接重用)時,Keep-Alive功能使用戶端到伺服器端的連接持續有效,當出現對伺服器的後繼請求時,Keep-Alive功能避免了建立或者重新建立連接。

http1.0協定中預設是關閉的,需要在http頭加入"Connection: Keep-Alive",才能啟用Keep-Alive;http1.1協議中預設啟用Keep-Alive,如果加入"Connection: close ",才關閉。目前大部分流覽器都是用http1.1協定,也就是說預設都會發起Keep-Alive的連接請求了,所以是否能完成一個完整的Keep- Alive連接就看伺服器設置情況。

從上面的分析來看,啟用Keep-Alive模式肯定更高效,性能更高。因為避免了建立及釋放連接的開銷。

以上兩個HTTP請求頭分別來自不同的流覽器,用這種方式請求,在一定概率上,每次請求都會讓伺服器以為是來自不同的流覽器發出的,使得伺服器會返回完整的HTML頁面給爬蟲端,爬蟲端就可以做出相應的解析,若是返回錯誤頁面、存在頁面、或者直接返回一串爬蟲無法解析的無效資訊,那麼提取資料從何談起。使用測試請求頭對爬取資料進行請求測試,若連接爬取多個頁面均無出現明顯錯誤,即可進入正式爬取階段。

但是使用類比請求頭的方式對於非同步Ajax載入的資料不好直接定位採集,需要對非同步Ajax載入的位置進行請求的重新類比,要先分析非同步請求,再類比載入請求再請求一次伺服器,對於爬蟲系統來說是很消耗性能的。所以,一般如果採集多種非同步資料,可以採用自動化測試工具Selenium模擬流覽器。

Selenium 是什麼?一句話,自動化測試工具。它支持各種流覽器,包括 Chrome,Safari,Firefox 等主流介面式流覽器,如果你在這些流覽器裡面安裝一個 Selenium 的外掛程式,那麼便可以方便地實現Web介面的測試;安裝一下 Python 的 Selenium 庫,再安裝好 PhantomJS,就可以實現 Python+Selenium+PhantomJS 的一整套體系的連接了!PhantomJS 用來渲染解析JavaScirpy,Selenium 用來驅動以及與 Python 的對接,Python 進行後期的處理。

利用Selenium模擬的流覽器能夠更加逼真模擬真實Web請求環境,對於Ajax非同步載入的資料可以快速定位。

但是在進行模擬爬取時,若觸發網站的防爬機制,那麼就必須進行多IP的模擬和對爬取執行緒採取暫時暫停,兩者相結合的辦法來測試防爬機制的臨界點,對於多IP的模擬可以採取二分折半測試的辦法,先取一個比較長的暫停時間。然後如果能使程式正常進行就再縮短一倍時間,否則擴大一倍時間,直到有一個臨近的值或者區間,再對該臨界值或者區間取亂數暫停爬取執行緒。

具體請求代碼如下:

def get_soup (url) :

logger.info('Prepare analytical this URL:')

logger.info(url)

print('準備解析該連結:', url)

# dis = { url : url }

# print(dis)

try:

try:

# 偽裝成流覽器

headers = [{

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',

}, {

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2',

}, {

'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/*,*/*;q=0.8',

'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',

'Cache-Control': 'max-age=0',

'Connection': 'keep-alive',

'User-Agent': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17',

},

]

header = random.choice(headers)

# 使用代理IP

proxy_ips = [

{'': '117.90.3.226:9000'},

{'': '210.136.19.75:8080'},

{'': '118.186.219.164:8080'},

{'': '121.232.147.177:9000'},

{'': '117.90.5.48:9000'},

{'': '138.186.84.129:8080'},

{'': '125.81.105.134:8998'},

{'': '114.253.210.125:8118'},

{'': '60.160.128.10:9999'},

]

proxy_ip = random.choice(proxy_ips)

proxy_support = urllib.request.ProxyHandler(proxy_ip)

opener = urllib.request.build_opener(proxy_support)

urllib.request.install_opener(opener)

# 請求

sleep(0.2)

request = Request(url=url, headers=header)

sleep(0.3)

response = urlopen(request)

except (HTTPError, URLError) as e:

logger.error('URL Error or HTTPError:')

logger.error(e)

print("請求有問題", e)

return None

try:

the_page = response.read()

soup = BeautifulSoup(the_page, "html.parser")

# 判斷是否有驗證碼 (得到所有soup的title)

title_value = soup.title.string.encode('utf-8')

# 驗證碼頁面的title.encode('utf-8')

verification_code = "請輸入驗證碼".encode('utf-8')

# (出現驗證碼了){阻塞或者暫停6666秒}

if title_value == verification_code:

logger.warning('Boom.........verification_code now!!!!!!!!!!!!!!!!!!!!!!!!!!!')

logger.warning('sleeping.......')

sleep(2222)

# name = input("The bomb is about to explode,Please input your name: ")

# print("Hello,", name)

# logger.warning('The bomb is about to explode')

# logger.warning(name)

soup = get_soup(url)

logger.warning('(warning)Revisit the link:')

logger.warning(url)

return soup

except AttributeError as e:

logger.error('AttributeError(Request soup)')

logger.error(e)

return None

return soup

except Exception as e:

logger.error('another Exception(Request soup)')

logger.error(e)

return None

四、HTML網頁的解析

爬蟲請求成功後,返回Soup,即HTML的原始程式碼。

HTML頁面中包含著大量的文本、連結、圖片等資訊,所有的HTML都以,開始結束。所有的HTML原始程式碼中均包含著大量的如等標籤,眾多標籤構成了完整的HTML文檔。DOM全稱 Document Object Model,即文檔物件模型。將文檔抽象成一個樹型結構,文檔中的標籤、標籤屬性或標籤內容可以表示為樹上的結點。

HTML文檔轉換為HTML DOM節點樹如圖2所示:

圖2

使用BeautifulSoup解析這段代碼,能夠得到一個 BeautifulSoup 的物件,並能按照標準的縮進格式的結構輸出:

from bs4 import BeautifulSoup

soup = BeautifulSoup(html_doc)

print(soup.prettify())

anscstory

anscstory

幾個簡單的流覽結構化資料的方法:

☛Soup.title 輸出內容: ansc story

☛soup.title.name輸出內容: u'title'

☛soup.title.string輸出內容:u' ansc story '

將一段文檔傳入BeautifulSoup的構造方法,就能得到一個文檔的物件, 可以傳入一段字串或一個檔案控制代碼。

在Beautiful Soup中最常用的函數為find_all()和find()。

find_all() 方法搜索當前tag的所有tag子節點,並判斷是否符合篩檢程式的條件

find_all( name , attrs , recursive , text , **kwargs )

name 參數

name參數可以查找所有名字為name的tag,字串物件會被自動忽略掉。搜索 name參數的值可以是任一類型的篩檢程式。

keyword 參數

如果一個指定名字的參數不是搜索內置的參數名,搜索時會把該參數當作指定名字tag的屬性來搜索,如果包含一個名字為id的參數,Beautiful Soup會搜索每個tag的“id”屬性。

按CSS搜索

按照CSS類名搜索tag的功能非常實用,但標識CSS類名的關鍵字 class 在Python中是保留字,使用class做參數會導致語法錯誤。從Beautiful Soup的4.1.1版本開始,可以通過 class_ 參數搜索有指定CSS類名的tag。

text 參數

通過text參數可以搜素文檔中的字串內容,與 name 參數的可選值一樣,text 參數接受字串、規則運算式、清單、True。

limit 參數

find_all() 方法返回全部的搜索結構,如果文檔樹很大那麼搜索會很慢。如果我們不需要全部結果,可以使用limit參數限制返回結果的數量。效果與SQL中的limit關鍵字類似,當搜索到的結果數量達到limit的限制時,就停止搜索返回結果。

find(name,attrs,recursive,text,**kwargs)

find_all() 方法將返回文檔中符合條件的所有tag,儘管有時候我們只想得到一個結果。比如文檔中只有一個標籤,那麼使用 find_all() 方法來查找標籤就不太合適,使用 find_all 方法並設置 limit=1 參數不如直接使用 find() 方法。

Beautiful Soup將複雜HTML文檔轉換成一個複雜的樹形結構,每個節點都是一個Python物件,所有物件都可以歸為4個種類:Tag ,NavigableString ,BeautifulSoup , Comment 。所以在解析HTML時,即是在操作Beautiful Soup裡頭的一個個Python物件。Beautiful Soup提供了強大的函式程式庫,所以任何HTML(或XML)檔的任意節點資訊,都可以被提取出來,只要目標資訊的旁邊或附近有標記即可。

資料經過清洗過濾之後提取出來,寫入文字檔或者持久化到MySQL。對於已經持久化到MySQL的資料,一方面可以進一步對該主題資料進行資料採擷,另一方面可以利用Java強大的Web處理能力展示資料,利用純Javascript圖表庫ECharts, 進行資料的視覺化展示。

Next Article
喜欢就按个赞吧!!!
点击关闭提示