本篇是 python 爬蟲(chóng)的第三篇该肴,在前面兩篇 Python 爬蟲(chóng)第一篇(urllib+regex) 和 Python 爬蟲(chóng)第二篇(urllib+BeautifulSoup) 中介紹了如何獲取給定網(wǎng)址的網(wǎng)頁(yè)信息,并解析其中的內(nèi)容藐不。本篇將更進(jìn)一步匀哄,根據(jù)給定網(wǎng)址獲取并解析給定網(wǎng)址及其相關(guān)聯(lián)網(wǎng)址中的內(nèi)容。要實(shí)現(xiàn)這些功能雏蛮,我們需要解決以下問(wèn)題:
- 如何持續(xù)不斷的獲取網(wǎng)址涎嚼,并讀取相關(guān)內(nèi)容。
- 如何判斷網(wǎng)址是否已經(jīng)讀取過(guò)挑秉。
文中用到的代碼均已上傳到 github铸抑,在這里就不再貼出完整的代碼了。
如何持續(xù)不斷的獲取網(wǎng)址衷模,并讀取相關(guān)內(nèi)容鹊汛?
要想讀取網(wǎng)頁(yè)內(nèi)容,首先要獲取網(wǎng)頁(yè)的 url阱冶,但是我們又不能將所有的 url 都輸入到程序中刁憋,此時(shí)就需要我們從已知的 url 中解析出其他的 url,從而不間斷的獲取新的 url讀取新的內(nèi)容木蹬,獲取新的 url 可以通過(guò)解析含有 href 屬性的 a 標(biāo)簽來(lái)實(shí)現(xiàn)至耻,具體代碼如下:
for link in html.find_all(name='a', href=re.compile(r'https?://list|item.szlcsc.+')):
if len(self.__url_set) > self.__max_url_count:
return
url = link.get('href')
以上代碼解析出所有的 a 標(biāo)簽中的 href 屬性?xún)?nèi)容以 https://list.szlcsc
和 https://item.szlcsc
為開(kāi)頭的 url 連接。在這里還是設(shè)置了一個(gè)最大的 url 解析量「由于在測(cè)試中需要一個(gè)停止條件」镊叁,默認(rèn)值為1000尘颓。
從一個(gè) url 中獲取到更多的 url 后,我們?cè)撛趺慈プx然奁疤苹?以什么順序去讀取敛腌?不可能獲取一個(gè) url 就讀取一個(gè) url卧土,此時(shí)就需要一個(gè)保存 url 的地方「最好是可以順序保存順序取出的」,那么最好的方法就是使用隊(duì)列了像樊,以下是將 url 放入隊(duì)列的代碼:
for link in html.find_all(name='a', href=re.compile(r'https?://list|item.szlcsc.+')):
if len(self.__url_set) > self.__max_url_count:
return
url = link.get('href')
if url not in self.__url_set:
self.__url_set.add(url)
self.__url_queue.put(url)
以下是從隊(duì)列中取出 url 的代碼:
while not self.__url_queue.empty():
count = count + 1
url = self.__url_queue.get()
result = self.get_html(url)
以上兩段代碼完成了一個(gè) url 從存入隊(duì)列到從隊(duì)列中出的全過(guò)程尤莺。
如何判斷網(wǎng)址是否已經(jīng)讀取過(guò)?
這個(gè)問(wèn)題實(shí)際上就是 url 去重的問(wèn)題生棍,常用的 url 去重的方法主要有以下幾種:
- url保存在數(shù)據(jù)庫(kù)中(效率低)
- 將 url 保存到集合中颤霎,利用集合的無(wú)重復(fù)元素的特性來(lái)去重,缺點(diǎn)是占用空間大涂滴。
- 將 url 通過(guò) md5 等哈希算法后保存到集合中去重友酱,可以大幅度提高內(nèi)容利用率。
- 使用布隆過(guò)濾器「Bloom Filter」氢妈,在時(shí)間和空間方面有巨大的優(yōu)勢(shì)粹污,但是存在一定的誤算率,不適用于高準(zhǔn)確度的場(chǎng)合首量。
本篇我們使用集合來(lái)對(duì) url 進(jìn)行去重壮吩,其他方法大家可以自行搜索一下,網(wǎng)上有很多這方面的資料加缘。
集合中的元素?zé)o次序鸭叙,且不可重復(fù)。元素不可重復(fù)的特性用來(lái)對(duì) url 去重在合適不過(guò)了拣宏,通過(guò)判斷 url 是否已經(jīng)在集合中可以快速判斷該 url 是否已經(jīng)讀取過(guò)沈贝。具體看以下代碼:
if url not in self.__url_set:
self.__url_set.add(url)
self.__url_queue.put(url)
以上代碼首先判斷 url 是否存在于 __url_set 中,如果不存在則將該 url 添加到 __url_set 中勋乾,同時(shí)將次 url 放入讀取隊(duì)列中進(jìn)行讀取宋下。這樣既對(duì)得到的每個(gè) url 進(jìn)行讀取嗡善,又避免了多次讀取同一個(gè) url 造成資源的浪費(fèi)。