21世紀以來,在互聯(lián)網高速發(fā)展的背景下,互聯(lián)網上的信息呈現(xiàn)暴發(fā)式的增加,對應的提供人們檢索信息功能的搜索引擎也在飛速發(fā)展、更新和迭代。但現(xiàn)有的知名搜索引擎能夠觸及的互聯(lián)網內容用九牛一毛來形容也毫不為過。為了給細分領域的客戶提供更優(yōu)質的搜索體驗,建立一套自己的搜索引擎就十分重要了。建立一個搜索引擎一般來說需要做這樣幾件事:
1、利用網絡爬蟲自動下載網絡頁面;
2、對爬取結果建立高效快速的索引;
3、根據相關性對網絡進行準確的排序。
目前的爬蟲技術一般分為兩種:通用網絡爬蟲和主題網絡爬蟲。通用網絡爬蟲一般盡可能多的采集頁面,而一般不關心被采集頁面的順序與頁面主題的相關性。Google和百度等具有大型搜索引擎的公司均采用通用網絡爬蟲。主題網絡爬蟲則根據一個已經預定好的主題進行爬取采集,最終對采集結果進行匯總,其爬取頁面具有大量相關性。相對通用網絡爬蟲,主題網絡爬蟲所消耗的資源和網絡帶寬更少,所采集的主題相關性更強,頁面的利用率更高。
本期“安仔課堂”,ISEC實驗室的葉老師為大家詳細剖析下主題網絡爬蟲的幾個主要技術點。
一、遍歷算法
1738年,瑞典數(shù)學家歐拉( Leornhard Euler)解決了柯尼斯堡問題,由此,圖論誕生,歐拉也成為了圖論的創(chuàng)始人。圖由一些節(jié)點與連接這些節(jié)點的弧組成。我們可以把互聯(lián)網看成一張具有指向無數(shù)方向的浩瀚無邊的圖,每一張網頁為圖的一個節(jié)點,每個網頁中的超鏈接為圖中的弧。有了超鏈接,我們可以從任何一個網頁出發(fā),用圖的遍歷算法,自動訪問到每一個頁面,然后存儲所需要的信息。
圖的遍歷算法可以分為深度優(yōu)先搜索(Depth-First Search 簡稱DFS)和廣度優(yōu)先搜索(Breadth–First Search 簡稱BFS)。
由于深度優(yōu)先搜索的遍歷方式,在很多情況下會導致爬蟲在深度上過“深”地遍歷或者陷入黑洞,大多數(shù)爬蟲不采用深度優(yōu)先搜索,目前主題爬蟲比較常見的是廣度優(yōu)先搜索方式。
廣度優(yōu)先搜索遍歷URL策略的基本思路是:將新下載網頁中發(fā)現(xiàn)的鏈接直接插入待抓取URL隊列的末尾。也就是指網絡爬蟲會先抓取起始網頁中鏈接的所有網頁,然后再選擇其中的一個鏈接網頁,繼續(xù)抓取在此網頁中鏈接的所有網頁。
圖1
如圖1,廣度優(yōu)先遍歷搜索(BFS)的訪問順序為:A->B->C->D->E->F->H->G->I 深度優(yōu)先搜索策略從起始網頁開始,選擇一個URL進入,分析這個網頁中的URL,選擇其中一個再進入。如此一個鏈接接著一個鏈接地抓取下去,一路走到黑,直到處理完一條路線之后再處理下一條路線。如圖1,深度優(yōu)先遍歷(DFS)的訪問順序為:A->B C D E->H->I F->G
不管是哪種方式,理論上都可以保證訪問到所有的節(jié)點。但是工程上基于穩(wěn)定性等要求一般采用的都是BFS方式。
二、網絡爬蟲
本文使用Python語言作為主開發(fā)語言。在Python中使用urllib.urlopen(url[, data[, proxies]]) :創(chuàng)建一個表示遠程url的類文件對象,然后像本地文件一樣操作這個類文件對象來獲取遠程數(shù)據。
Python可以使用urllib請求頁面獲取網頁HTML信息,實現(xiàn)如下:
from urllib.request import urlopen
html = urlopen(‘http: www.baidu.com’)
得到源代碼后即可使用Xpath或者BeautifulSoup4解析HTML元素,提取所需要數(shù)據。以上,即完成一個簡單的Web數(shù)據采集流程。
但是具體的業(yè)務工程往往不是一個簡單的流程而已,有時候會采集非結構化數(shù)據,需要再由工程人員寫下載器,進行非結構化數(shù)據的提取;有時候結構化數(shù)據是異步加載,需要我們模擬加載的JavaScript代碼,再對服務器進行一次請求;對于需要代理才能訪問的網站,需要再添加代理IP;還有采集的效率等等一系列問題。
三、HTTP請求頭的設計
瀏覽器與服務器交互是基于超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol),HTTP是互聯(lián)網上應用最為廣泛的一種網絡協(xié)議。HTTP是一個基于TCP/IP通信協(xié)議來傳遞數(shù)據(HTML 文件, 圖片文件, 查詢結果等)。
在爬取網站內容時,HTTP協(xié)議中請求頭的模擬至關重要,請求頭不正確將會導致目標站點返回錯誤的狀態(tài)碼和無效的字符;例如在對某同城租房模塊的數(shù)據采集中,先是使用chrome瀏覽器請求租房頁面,查找到瀏覽器請求目標站點的數(shù)據包,分析請求頭,然后模擬了一個類似的請求頭,代碼如下:
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', 建議保持打開狀態(tài)。
我們知道HTTP協(xié)議采用“請求-應答”模式,當使用普通模式,即非KeepAlive模式時,每個請求—應答客戶端和服務器都要新建一個連接,完成之后立即斷開連接(HTTP協(xié)議為無連接的協(xié)議);當使用Keep-Alive模式(又稱持久連接、連接重用)時,Keep-Alive功能使客戶端到服務器端的連接持續(xù)有效,當出現(xiàn)對服務器的后繼請求時,Keep-Alive功能避免了建立或者重新建立連接。
http 1.0協(xié)議中默認是關閉的,需要在http頭加入"Connection: Keep-Alive",才能啟用Keep-Alive;http 1.1協(xié)議中默認啟用Keep-Alive,如果加入"Connection: close ",才關閉。目前大部分瀏覽器都是用http1.1協(xié)議,也就是說默認都會發(fā)起Keep-Alive的連接請求了,所以是否能完成一個完整的Keep- Alive連接就看服務器設置情況。
從上面的分析來看,啟用Keep-Alive模式肯定更高效,性能更高。因為避免了建立及釋放連接的開銷。
以上兩個HTTP請求頭分別來自不同的瀏覽器,用這種方式請求,在一定概率上,每次請求都會讓服務器以為是來自不同的瀏覽器發(fā)出的,使得服務器會返回完整的HTML頁面給爬蟲端,爬蟲端就可以做出相應的解析,若是返回錯誤頁面、存在頁面、或者直接返回一串爬蟲無法解析的無效信息,那么提取數(shù)據從何談起。使用測試請求頭對爬取數(shù)據進行請求測試,若連接爬取多個頁面均無出現(xiàn)明顯錯誤,即可進入正式爬取階段。
但是使用模擬請求頭的方式對于異步Ajax加載的數(shù)據不好直接定位采集,需要對異步Ajax加載的位置進行請求的重新模擬,要先分析異步請求,再模擬加載請求再請求一次服務器,對于爬蟲系統(tǒng)來說是很消耗性能的。所以,一般如果采集多種異步數(shù)據,可以采用自動化測試工具Selenium模擬瀏覽器。
Selenium 是什么?一句話,自動化測試工具。它支持各種瀏覽器,包括 Chrome,Safari,Firefox 等主流界面式瀏覽器,如果你在這些瀏覽器里面安裝一個 Selenium 的插件,那么便可以方便地實現(xiàn)Web界面的測試;安裝一下 Python 的 Selenium 庫,再安裝好 PhantomJS,就可以實現(xiàn) Python+Selenium+PhantomJS 的一整套體系的連接了!PhantomJS 用來渲染解析JavaScirpy,Selenium 用來驅動以及與 Python 的對接,Python 進行后期的處理。
利用Selenium模擬的瀏覽器能夠更加逼真模擬真實Web請求環(huán)境,對于Ajax異步加載的數(shù)據可以快速定位。
但是在進行模擬爬取時,若觸發(fā)網站的防爬機制,那么就必須進行多IP的模擬和對爬取線程采取暫時暫停,兩者相結合的辦法來測試防爬機制的臨界點,對于多IP的模擬可以采取二分折半測試的辦法,先取一個比較長的暫停時間。然后如果能使程序正常進行就再縮短一倍時間,否則擴大一倍時間,直到有一個臨近的值或者區(qū)間,再對該臨界值或者區(qū)間取隨機數(shù)暫停爬取線程。
具體請求代碼如下:
def get_soup (url) :
logger.info('Prepare analytical this URL:')
logger.info(url)
print('準備解析該鏈接:', url)
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; 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 = [
{'http:': '117.90.3.226:9000'},
{'http:': '210.136.19.75:8080'},
{'http:': '118.186.219.164:8080'},
]
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')
verification_code = "請輸入驗證碼".encode('utf-8')
if title_value == verification_code:
logger.warning(....verification_code now!!!!!')
sleep(2222)
# name = input("The bomb is about to explode,Please input your name:\n")
# print("Hello,", 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文檔轉換為HTML DOM節(jié)點樹如圖2所示:
圖2
使用BeautifulSoup解析這段代碼,能夠得到一個 BeautifulSoup 的對象,并能按照標準的縮進格式的結構輸出:
幾個簡單的瀏覽結構化數(shù)據的方法:
將一段文檔傳入BeautifulSoup的構造方法,就能得到一個文檔的對象, 可以傳入一段字符串或一個文件句柄。
在Beautiful Soup中最常用的函數(shù)為find_all()和find()。
find_all() 方法搜索當前tag的所有tag子節(jié)點,并判斷是否符合過濾器的條件
find_all( name , attrs , recursive , text , **kwargs )
name 參數(shù)
name參數(shù)可以查找所有名字為name的tag,字符串對象會被自動忽略掉。搜索 name參數(shù)的值可以是任一類型的過濾器。
keyword 參數(shù)
如果一個指定名字的參數(shù)不是搜索內置的參數(shù)名,搜索時會把該參數(shù)當作指定名字tag的屬性來搜索,如果包含一個名字為id的參數(shù),Beautiful Soup會搜索每個tag的“id”屬性。
按CSS搜索
按照CSS類名搜索tag的功能非常實用,但標識CSS類名的關鍵字 class 在Python中是保留字,使用class做參數(shù)會導致語法錯誤。從Beautiful Soup的4.1.1版本開始,可以通過 class_ 參數(shù)搜索有指定CSS類名的tag。
text 參數(shù)
通過text參數(shù)可以搜素文檔中的字符串內容,與 name 參數(shù)的可選值一樣,text 參數(shù)接受字符串、正則表達式、列表、True。
limit 參數(shù)
find_all() 方法返回全部的搜索結構,如果文檔樹很大那么搜索會很慢。如果我們不需要全部結果,可以使用limit參數(shù)限制返回結果的數(shù)量。效果與SQL中的limit關鍵字類似,當搜索到的結果數(shù)量達到limit的限制時,就停止搜索返回結果。
find(name,attrs,recursive,text,**kwargs)
find_all() 方法將返回文檔中符合條件的所有tag,盡管有時候我們只想得到一個結果。比如文檔中只有一個標簽,那么使用 find_all() 方法來查找標簽就不太合適,,使用 find_all 方法并設置 limit=1 參數(shù)不如直接使用 find() 方法。
Beautiful Soup將復雜HTML文檔轉換成一個復雜的樹形結構,每個節(jié)點都是一個Python對象,所有對象都可以歸為4個種類:Tag ,NavigableString ,BeautifulSoup , Comment 。所以在解析HTML時,即是在操作Beautiful Soup里頭的一個個Python對象。Beautiful Soup提供了強大的函數(shù)庫,所以任何HTML(或XML)文件的任意節(jié)點信息,都可以被提取出來,只要目標信息的旁邊或附近有標記即可。
數(shù)據經過清洗過濾之后提取出來,寫入文本文件或者持久化到MySQL。對于已經持久化到MySQL的數(shù)據,一方面可以進一步對該主題數(shù)據進行數(shù)據挖掘,另一方面可以利用Java強大的Web處理能力展示數(shù)據,利用純Javascript圖表庫ECharts, 進行數(shù)據的可視化展示。
廈門安勝網絡科技有限公司,廈門市美亞柏科信息股份有限公司控股子公司,是國內領先的網絡安全檢測產品及服務提供商;秉承“創(chuàng)新為安,服務致勝”的經營理念,專注于網絡安全類產品的生產與服務。
“ISEC實驗室”作為公司新技術和新產品的預研基地,秉承“我的安全,我做主”的理念,專注于網絡安全領域前沿技術研究,提供網絡安全培訓、應急響應、安全檢測等服務。曾承接北京奧運會、上海世博會、廣州亞運會、杭州G20峰會、金磚“廈門會晤”等大型活動網絡安全保障工作。
未來,安勝將繼續(xù)以昂揚的姿態(tài)、在網絡安全領域不斷深耕,為建設網絡強國做出更大貢獻!
- 蜜度索驥:以跨模態(tài)檢索技術助力“企宣”向上生長
- 金屏獎重磅環(huán)節(jié) | 遇見2024·預見2025 —— 燈少年度演講,啟幕未來之門
- 規(guī)模升級,2025 ChinaJoy Express游戲試玩區(qū)招商全新開啟
- 會員客廳|第十六屆虎嘯獎宣講會·北京站,誠邀參與!
- 捷途怎么就火了?
- 聚焦行業(yè)前沿,共享無限商機,2025九州汽車生態(tài)博覽會全面啟動!
- 倒計時7天--“2025第四屆東盟軌道交通國際峰會”最新情況公布|Only 7 Days Away--The 4th ASEAN Rail Summit 2025
- 再上新階 CDCE2024國際數(shù)據中心及云計算展圓滿閉幕 2025年11月上海再相聚
- 2025中國智能電動汽車科技與供應鏈展覽會 邀請函
- 2025戶外&鞋服箱包營銷創(chuàng)新論壇定檔3月上海舉辦
- 智能無界,勇敢生長!2024年中國物聯(lián)網產業(yè)大會暨第21屆慧聰品牌盛會盛大召開!
免責聲明:本網站內容主要來自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網站出現(xiàn)的信息,均僅供參考。本網站將盡力確保所提供信息的準確性及可靠性,但不保證有關資料的準確性及可靠性,讀者在使用前請進一步核實,并對任何自主決定的行為負責。本網站對有關資料所引致的錯誤、不確或遺漏,概不負任何法律責任。任何單位或個人認為本網站中的網頁或鏈接內容可能涉嫌侵犯其知識產權或存在不實內容時,應及時向本網站提出書面權利通知或不實情況說明,并提供身份證明、權屬證明及詳細侵權或不實情況證明。本網站在收到上述法律文件后,將會依法盡快聯(lián)系相關文章源頭核實,溝通刪除相關內容或斷開相關鏈接。