在知乎上看過(guò)很多爬蟲(chóng)相關(guān),一直沒(méi)有動(dòng)手,現(xiàn)在開(kāi)始get my hand dirty.
本篇在學(xué)習(xí)知乎大神xzld的Web crawler with Python - 03.豆瓣電影TOP250基礎(chǔ)上,簡(jiǎn)單爬取了糗百上的笑話。
結(jié)果.png
任務(wù)目標(biāo)
利用python爬取糗事百科上的笑話。
任務(wù)理解
在做任何爬蟲(chóng)之前,我們首先需要了解一下想要爬取的對(duì)象
- 打開(kāi):用火狐瀏覽器打開(kāi)糗事百科,打開(kāi)開(kāi)發(fā)者工具(F12)
- 查看 :選中任意一條笑話,鼠標(biāo)右鍵后點(diǎn)擊查看,我們就可以看到該條笑話在HTML中位于的位置
- 觀察 :仔細(xì)觀察其標(biāo)簽,因?yàn)橹笪覀儗⒏鶕?jù)其標(biāo)簽來(lái)定位。
通過(guò)觀察我們發(fā)現(xiàn),笑話內(nèi)容位于<div class=content>的<span>標(biāo)簽下。
那么我們的任務(wù)即轉(zhuǎn)變?yōu)椋?br>
在糗事百科的HTML中找到<.div class=content>的<span>標(biāo)簽的文本內(nèi)容。

因此,我們將任務(wù)即可分為三部分:
- 下載:將糗事百科頁(yè)面的HTML內(nèi)容下載下來(lái),這部分我們將使用requests包
- 解析:根據(jù)標(biāo)簽查找到文本內(nèi)容并存儲(chǔ),這部分使用BeautifulSoup包。
- 輸出:將文本內(nèi)容格式化輸出,這部分我們將使用codecs包。
任務(wù)進(jìn)行
環(huán)境準(zhǔn)備
import warnings
warnings.filterwarnings('ignore')
import requests
from bs4 import BeautifulSoup
import codecs
引入requests,BeautifulSoup,codecs及warnings包。warnings包主要用來(lái)忽略編碼過(guò)程中的警告提示,我常喜歡把它寫(xiě)在編碼前
下載頁(yè)面
我們使用requests中的get方法來(lái)獲取頁(yè)面,
URL="https://www.qiushibaike.com/"
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0'}
html=requests.get(URL,headers=header).content
簡(jiǎn)單介紹代碼內(nèi)容
- 第一行代碼指定網(wǎng)頁(yè)
- 第二行代碼指定請(qǐng)求頭User-Agent(表示瀏覽器類(lèi)型),用來(lái)將爬蟲(chóng)偽裝成瀏覽器。
- 第三行利用requests.get().content 獲取指定網(wǎng)頁(yè)源代碼。
注意reuqests.get(URL,headers=header)中headers不能省略

一般,瀏覽器在向服務(wù)器發(fā)送請(qǐng)求的時(shí)候,會(huì)有一個(gè)請(qǐng)求頭——User-Agent,它用來(lái)標(biāo)識(shí)瀏覽器的類(lèi)型.當(dāng)我們使用requests來(lái)發(fā)送請(qǐng)求的時(shí)候,默認(rèn)的User-Agent是python-requests/2.8.1(后面的數(shù)字可能不同,表示版本號(hào)),通常我們需要要將User-Agent偽裝成瀏覽器的,來(lái)解決某些網(wǎng)頁(yè)反爬蟲(chóng)的問(wèn)題。這是一種簡(jiǎn)單的反爬蟲(chóng)機(jī)制
解析頁(yè)面
通過(guò)上部我們的得到網(wǎng)頁(yè)源代碼,但是看起來(lái)非常的亂,毫無(wú)頭緒,就像一鍋東北亂燉。然后通過(guò)BeautifulSoup,包如其名,總能把亂糟糟的菜熬成很漂亮的一鍋湯,讓你很方便的找到需要的內(nèi)容。
- 熬湯:通過(guò)BeautifulSoup命令間html內(nèi)容轉(zhuǎn)換為beautifulsoup格式
soup=BeautifulSoup(html)

如上圖,BeautifulSoup將源代碼很好的處理為了標(biāo)簽加內(nèi)容的格式,非常利于我們來(lái)查找內(nèi)容。
- 找菜:湯熬好,就可以根據(jù)我們給出的標(biāo)簽來(lái)找菜了
joks=soup.find_all('div',attrs={'class':'content'})
jok_list=[]
for joks in jokss:
jok=joks.find('span').getText()
jok_list.append(jok)
- 第一行利用find_all找到所有標(biāo)簽為<div class=content>內(nèi)容
圖片.png - 第二行創(chuàng)建一個(gè)空列表jok_list,用來(lái)存儲(chǔ)之后找到的笑話
- 第三行建立一個(gè)循環(huán),利用find依次查找每一個(gè)<div class=content>中的<span>標(biāo)簽并獲取其中的文本內(nèi)容,利用append函數(shù)存儲(chǔ)到jok_list中
- 加菜:當(dāng)然我們注意到,糗百涉及到翻頁(yè)。我們還需要解決翻頁(yè)的問(wèn)題,這個(gè)問(wèn)題最簡(jiǎn)單的方法就是找到下一頁(yè)的鏈接,再重復(fù)之前的步驟即可。
next_page=soup.find('ul',{'class':'pagination'}).find_all('a')[-1]['href']
next_page=URL[:-1]+next_page

點(diǎn)擊下一頁(yè),查看元素。我們發(fā)現(xiàn)下一頁(yè)的鏈接再<ul,class=pagination>的最后一個(gè)標(biāo)簽<'a'>下。因?yàn)槭褂胒ind只能返回匹配的第一個(gè)對(duì)象,因此這里我們使用find_all找到所有匹配對(duì)象的列表。再通過(guò)soup.find('ul',{'class':'pagination'}).find_all('a')[-1]定位到最后一個(gè)對(duì)象,即包含下一頁(yè)信息的對(duì)象.
注意
以第一頁(yè)為例得到的結(jié)果為* '/8hr/page/2/' ,需要與 URL='https://www.qiushibaike.com/'拼接。但是如果直接連在一起得到結(jié)果為
'https://www.qiushibaike.com//8hr/page/2’多了一條‘/’因此,使用URL[-1]+next_page才能得到正確的鏈接。 'https://www.qiushibaike.com/8hr/page/2’ *
存儲(chǔ)
codecs.open('joks','wb',encoding='utf-8') as fp:
fp.write(u'{jok_list}\n'.format(jok_list='\n'.join(jok_llist)))
任務(wù)總結(jié)
import requests
from bs4 import BeautifulSoup
import warnings
import codecs
warnings.filterwarnings('ignore')
def download_page(url):
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0'}
html=requests.get(URL,headers=header).content
return html
def parsel_html(html):
soup=BeautifulSoup(html)
joks=soup.find_all('div',{'class':'content'})
jok_list=[]
for joks in jokss:
jok=joks.find('span').getText()
jok_list.append(jok)
next_page=soup.find('ul',{'class':'pagination'}).find_all('a')[-1]['href']
if next_page:
return jok_list,URL[:-1]+next_page
return jok_list,None
def main():
URL="https://www.qiushibaike.com/"
with codecs.open('joks','wb',encoding='utf-8') as fp:
while URL:
HTML=download_page(URL)
JOK,URL=parsel_html(HTML)
fp.write(u'{JOK}\n'.format(JOK='\n'.join(JOK)))
if __name__ == '__main__':
main()

