1.爬蟲結(jié)構(gòu)
從爬蟲的結(jié)構(gòu)上來看,追簡單的爬蟲包括任務(wù)隊(duì)列、頁面下載和頁面解析三個(gè)部分。
import Queue
init_url = 'xxxx' #初始化頁面
queue = Queue.Queue() #任務(wù)隊(duì)列
fetch_urls = set() #已訪問頁面集合
queue.put(init_url)
fetch_urls.add(init_url)
while True:
if queue.size()>0:
url = queue.get()
html = download(url)
data = parse(html)
urls = data['urls']
for url in urls:
if url not in fetch_urls:
fetch_urls.add(url)
queue.put(url)
else:
break
上面代碼實(shí)現(xiàn)了一個(gè)簡單的爬蟲,雖然是偽代碼,但稍作修改就可以運(yùn)行。
2.糗事百科
(1)頁面分析
每一個(gè)爬蟲都需要先分析一下頁面結(jié)構(gòu),這樣才能使用程序正確的獲取相關(guān)的內(nèi)容。

首頁中在“熱門”標(biāo)簽下,每頁列出了20個(gè)內(nèi)容,在頁面底部有分頁區(qū)域。

F12打開開發(fā)者工具,每個(gè)內(nèi)容由一個(gè)div包括。查找class屬性為"article block untagged mb15",就可以獲取當(dāng)前頁面所有的內(nèi)容標(biāo)簽。對(duì)每一個(gè)內(nèi)容,繼續(xù)查找用戶名以及用戶鏈接,文本內(nèi)容,還有點(diǎn)贊數(shù)量和評(píng)論數(shù)量。

上圖是分頁部分的代碼,從中可以提取到相關(guān)的url地址。
(2)頁面分析代碼
- 查找所有的article
soup = BeautifulSoup(html,'html5lib')
articles = soup.find_all("div",attrs={"class":"article block untagged mb15"})
- 獲取單個(gè)article中的用戶信息
for article in articles:
#獲取用戶信息
author = article.find('div',attrs={'class':'author'})
author_as = article.find_all('a')
#這里我們會(huì)找到兩個(gè)a標(biāo)簽,第一個(gè)標(biāo)簽是頭像照片,第二個(gè)標(biāo)簽是用戶名和用戶鏈接,這里需要的是后者。
user = author_as[1]
userlink = user['href']
username = user['title']
#這里再展示一下別的方法,我們可以觀察到每個(gè)article中只有一個(gè)h2標(biāo)簽
#h2的父標(biāo)簽就是上面的author_as[1]
h2 = article.find('h2')
h2p = h2.parent#這樣就可以參照上面的代碼查找用戶名和用戶鏈接
- 獲取內(nèi)容文本
content = article.find('div',attrs={'class':'content'}).find('span').text
#這里用了一句代碼就獲取了內(nèi)容文本,實(shí)際上它執(zhí)行了三條語句
#第一步就是獲取class屬性為‘content’的div標(biāo)簽,第二步是找到
#它下屬的span標(biāo)簽,獲取文本采用的是text方法。這里要注意獲取文本內(nèi)容也可以使用string方法,
#但是如果文本中有其它html標(biāo)簽就會(huì)獲取失敗。
- 獲取點(diǎn)贊信息
#點(diǎn)贊信息和評(píng)論量在class='stats'的div標(biāo)簽下
#如果直接從上到下查找未免顯得過于繁瑣,可以直接查找i標(biāo)簽
#在查到標(biāo)簽的過程中要盡量采用最簡便的方法
i_list = article.find('i')
votenum = i_list[0].string
commentnum = i_list[1].string
- 查找url
url的查找是一個(gè)非常重要的內(nèi)容,否則爬蟲就沒法繼續(xù)運(yùn)行下去了。在頁面中出現(xiàn)的鏈接往往都是相對(duì)鏈接,這時(shí)候要拼裝成絕對(duì)鏈接。還有對(duì)一些鏈接進(jìn)行過濾,這里又涉及到正則表達(dá)式的內(nèi)容。正則表達(dá)式在分析文本中非常重要,以后也會(huì)介紹相關(guān)的內(nèi)容。
#這里只需要查找所有的a標(biāo)簽
alist = soup.find('a')
for a in alist:
]
這個(gè)例子的目的是查找所有的段子,實(shí)際上很多段子很長需要點(diǎn)到詳細(xì)頁才能看全,但是我們只需要截取一部分即可。還有就是,我們也不需要抓取用戶頁面信息。那么就需要過濾掉這些頁面,這里采用正則表達(dá)式。
import re#這句應(yīng)該放在最前面
pattern = re.compile(r'^/')
article_pattern = re.compile(r'^/(article|user)')
#這里有兩個(gè)模式(pattern),第一個(gè)我們只想爬取以"/"開頭的鏈接,
#這個(gè)鏈接代表相對(duì)于網(wǎng)站根目錄的地址。
#第二個(gè)模式,就是要排除以"/article"和"/user"開頭的地址
urls = []
for a in alist:
url = a['href']
if pattern.match(url) and not article_pattern.match(url) :
urls.append('http://www.qiushibaike.com'+url)
上面的代碼組裝一下就是parse函數(shù)的代碼,返回的數(shù)據(jù)包括糗事的信息以及要繼續(xù)爬取的url。
(3)頁面下載
頁面下載是很簡單的,是用requests是最方便的。當(dāng)然也有用urllib2,一開始我也用這個(gè),但是這個(gè)有些復(fù)雜而且有時(shí)候也不穩(wěn)定。這里要注意的就是requests編碼問題。
def download(url):
response = requests.get(url)
return response.text
上面的代碼很簡單,這里沒有考慮到出錯(cuò)問題,在實(shí)際使用中肯定要考慮這個(gè)。