
爬取目標(biāo)
爬取四塊簡單的簡書網(wǎng)頁,并做一定的分析。
- 第一塊是首頁熱門,網(wǎng)址就是
http://jianshu.com - 第二塊是簡書推薦,網(wǎng)址形如
http://www.itdecent.cn/recommendations/notes?max_id=1477985000 - 第三塊是熱門專題頁,網(wǎng)址形如
http://www.itdecent.cn/collections?order_by=score&page=1 - 第四塊就是簡書專題文章,網(wǎng)址形如
http://www.itdecent.cn/collections/16/notes?order_by=added_at&page=1
網(wǎng)絡(luò)請(qǐng)求和解析使用庫
- 從最簡單的開始,使用最好用的
requests做網(wǎng)絡(luò)訪問,并且使用操作方便的beautifulsoup來解析html。 - 沒有的話直接
pip install requests和pip install bs4安裝。
數(shù)據(jù)存儲(chǔ)
- 直接存儲(chǔ)為csv。在Excel文件中打開并分析。
- 此外嘗試使用下tinydb,一個(gè)文檔型數(shù)據(jù)庫。操作簡易。(只在部分內(nèi)容使用到)
首先我們做最簡單的第四塊
- 從網(wǎng)址
http://www.itdecent.cn/collections/16/notes?order_by=added_at&page=1的結(jié)構(gòu),就可以看出我們只需要修改網(wǎng)址末尾的page=x就可以不斷地訪問新的頁面爬取這個(gè)專題下的文章了,collections/后面的16代表程序員專題,order_by=added_at代表按收錄時(shí)間排序。下面就開始爬取吧。
import requests
from bs4 import BeautifulSoup
# 引入庫
base_url = 'http://www.itdecent.cn/collections/16/notes?order_by=added_at&page=%d' # page=0 和 page=1的效果相同
add_url = 1 # page數(shù)
num = 0 # 文章標(biāo)題計(jì)數(shù)
while(True):
try:
page = requests.request('get', base_url% add_url).content
# 將基礎(chǔ)網(wǎng)址和頁數(shù)拼接得到實(shí)際網(wǎng)址,使用request的get方法獲取響應(yīng),再用content方法得到內(nèi)容
soup = BeautifulSoup(page)
# 使用BeautifulSoup分析頁面,這里并沒有指定解析器,會(huì)自動(dòng)選取可獲得的最優(yōu)解析器
# BeautifulSoup會(huì)報(bào)一個(gè)warning要你選擇解析器,可以忽略
article_list = [i.get_text() for i in soup.select(".title a")]
# 這里使用了BeautifulSoup的選擇器soup.select,它會(huì)返回一個(gè)被選取的對(duì)象列表,我們使用列表推導(dǎo),對(duì)每個(gè)對(duì)象獲取其中的文字再組成列表。
# 選擇器使用見下文
for i in article_list:
# 將文章列表打印出來
num+=1
print(num, ' ', i)
add_url += 1
except Exception as e:
# 異常分析,打印出異常信息
print(e)
break # 這里使用break退出循環(huán),也可注釋掉該句,不斷循環(huán)
-
結(jié)果如下:
-
可以看出我們成功地爬取了內(nèi)容。其實(shí)本次爬取的關(guān)鍵在于soup.select選擇器的內(nèi)容。而選擇器內(nèi)容該如何獲取呢,它類同css選擇器(規(guī)則如下),我們可以分析網(wǎng)頁源碼,根據(jù)規(guī)則寫出。
-
但是我們還可以使用更便捷的方法,不需要知道額外的知識(shí)就解決,那就是使用SelectorGadget,它的chrome插件,非常好用,安裝后點(diǎn)擊使用,然后直接在你要爬取的網(wǎng)頁上選擇你要爬取的內(nèi)容,這時(shí)一系列內(nèi)容會(huì)被標(biāo)黃,但是可能其中有些你不需要的內(nèi)容,再點(diǎn)一下它們,它們會(huì)被標(biāo)記為紅色,就不會(huì)被選擇器選中,這時(shí)你所需要的選擇器內(nèi)容就在下方顯示出來了,如下圖,黃色的標(biāo)題就被選中,最下的藍(lán)色選中文字即為自動(dòng)生成的選擇器內(nèi)容:
這樣,我們成功解決了選擇器的問題,獲取到了我們需要的內(nèi)容。
其實(shí)還有一個(gè)關(guān)鍵點(diǎn)在于這樣的網(wǎng)址是如何獲取的呢,一般我們?cè)L問簡書可能并不會(huì)遇到這樣形式的網(wǎng)址,下文中我們會(huì)說明。
接著讓我們來看看首頁熱門文章
- 我們先通過上面的方法獲取文章標(biāo)題的選擇器,它也是
soup.select(".title a")。 - 和上面不同的是,首頁的網(wǎng)址只有一個(gè),也沒有一個(gè)明顯的頁數(shù)遞增規(guī)律,但是首頁下方會(huì)有一個(gè)更多的按鈕。讓我們使用F12開發(fā)者工具選取審查元素(快捷鍵Ctrl+Shift+C)選中按鈕查看這個(gè)按鈕的信息。
- 我們可以看到button標(biāo)簽里有個(gè)
data-url屬性,它是一個(gè)相對(duì)路徑,末尾是page=2,將它加上簡書域名,嘗試一下,發(fā)現(xiàn)就是下一頁的信息。于是,我們可以通多獲取button標(biāo)簽,讀取它的屬性來訪問以繼續(xù)爬取。 - 此外,我們升級(jí)一下解析器,讓html的解析速度變快些,下載lxml(我下載的是cp35-cp35m-win_amd64.whl版本,安裝成功),使用
pip install x.whl(x為 whl文件名)安裝。然后我們可以在Beautifulsoup中指定解析器了。 - 這次我們將爬取到的首頁熱門文章標(biāo)題信息保存為csv文件,以供后續(xù)處理。
import requests
from bs4 import BeautifulSoup
import csv # 引入csv模塊,讀寫csv文件
import datetime # 引入日期時(shí)間模塊
base_url = 'http://jianshu.com'
def shouYeReMen():
add_url = '' # 先置為空字符串
title_list = [] # 文章標(biāo)題列表
for i in range(15): # 首頁熱門實(shí)際為15頁,一開始可以設(shè)大些讓程序自動(dòng)退出來看到底有多少頁
try:
first_page = requests.get(base_url+ add_url).content
soup = BeautifulSoup(first_page, "lxml")
title_list += [i.get_text() for i in soup.select(".title a")]
# 以上和上一個(gè)爬蟲類同
try:
# print(soup.select(".ladda-button"))
add_url = soup.select(".ladda-button")[-1].get("data-url")
# 使用get方法獲取button的標(biāo)簽屬性信息作為額外的url
# 這里使用try,在最后一頁沒有button時(shí)會(huì)拋出異常
except:
# 在異常處理中通過break退出循環(huán)
break
except requests.exceptions.ConnectionError: # 有可能請(qǐng)求過多導(dǎo)致服務(wù)器拒絕連接
status_code = "Connection refused"
print(status_code)
time.sleep(60)
# 我們睡眠一分鐘后再爬
with open(datetime.datetime.now().strftime('%Y_%m_%d-%H_%M_%S')+'.csv', 'w', newline='', encoding='utf-8') as f:
# 在腳本當(dāng)前文件目錄下新建以當(dāng)前時(shí)間命名的csv文件,使用utf8編碼
writer = csv.writer(f)
# 傳入文件描述符構(gòu)建csv寫入器
writer.writerow(title_list)
# 將本次爬取的所有文章列表寫在一行中
print("have_done!")
import time
# 最后,我們循環(huán)爬取首頁信息,為了減輕服務(wù)器負(fù)擔(dān),也避免爬蟲請(qǐng)求被拒絕,我們每隔30秒爬取一次
while True:
shouYeReMen()
time.sleep(30)
-
爬取結(jié)果如下

- 現(xiàn)在我們來處理下這些數(shù)據(jù),使用分詞并保存熱點(diǎn)詞匯,在excel中查看熱點(diǎn)詞隨時(shí)間變化情況。
- 我們使用友好的中文分詞庫結(jié)巴分詞。使用
pip install jieba安裝。
import jieba
from collections import Counter
# 引入便捷的Counter函數(shù),可以看作一個(gè)計(jì)數(shù)器,計(jì)算元素在列表中的出現(xiàn)次數(shù)
# Counter([1,2,3,1])的輸出為Counter({1: 2, 2: 1, 3: 1})
import csv
def word_frequency(text):
# 定義詞頻統(tǒng)計(jì)函數(shù)
words = [word for word in jieba.cut(text, cut_all=False) if len(word) >= 2]
# 這里我們直接使用jieba.cut函數(shù)來分析文本的詞匯,為了方便,我們先選取2個(gè)字以上的詞統(tǒng)計(jì)
# 進(jìn)一步可以自定義詞庫,去掉與增加某些詞
c = Counter(words)
# 統(tǒng)計(jì)詞頻,并利用Counter的方法返回頻率最高的18個(gè)(詞匯,頻率)的元組列表
return c.most_common(18)
import os; os.chdir(r'E:\python\shouye')
# 這里我使用了系統(tǒng)庫,改變當(dāng)前所處路徑,也就是改到下面讀取和保存文件的路徑
import glob
result = open('result.csv', 'a', newline='', encoding='gb2312')
# 這里編碼為gb2312,以便直接在excel中打開查看
writer = csv.writer(result)
filelist = glob.glob('2016_*.csv')
# 使用glob獲取當(dāng)前路徑下所有以2016_開頭的csv文件名的列表,順序?yàn)槲募樞?num=1 # 打印輸出計(jì)數(shù)
for file in filelist:
with open(file, 'r', encoding='utf-8') as f:
line = f.readline()
# 讀取存有信息的一行
row = [(word+'-'+str(freq)) for word, freq in word_frequency(line)]
writer.writerow(row)
# 以 word, freq = (w, f) 解包返回的詞頻數(shù)據(jù),并組合word和freq(使用str()將freq由數(shù)字轉(zhuǎn)化為字符串類型),寫入文件
print("haha",num)
num+=1
result.close()
# 記得關(guān)閉文件
- 最后我們打開EXCEL查看result.csv文件,得到如下結(jié)果。每條記錄的間隔是半分多鐘,可以看到簡書的出現(xiàn)頻率還是挺高的(在我爬的600條數(shù)據(jù)中,'簡書'幾乎一直是熱詞),估計(jì)是目前的簡書程序員專題活動(dòng)的影響(它們的文章標(biāo)題都包含'簡書'),同時(shí)看出'人生','如何'之類的詞出現(xiàn)頻率也不低。
間隔約半分鐘的簡書熱詞變化
再進(jìn)一步,爬取第三塊-熱門專題頁
-
我們?cè)跒g覽器中來到簡書的專題廣場頁面,再次打開發(fā)者工具,點(diǎn)擊紅框切換到Network分析界面。
-
然后向下滾動(dòng)簡書頁面,一小段之后,我們發(fā)現(xiàn)網(wǎng)絡(luò)請(qǐng)求欄有新的條目出現(xiàn),而變化的第一個(gè)的名稱就是我們需要的請(qǐng)求地址了。
- 我們直接copy鏈接,獲得
http://www.itdecent.cn/collections?page=2&_=1478182353282
Paste_Image.png - 我們只取
&前面部分就可以訪問了,在瀏覽器里嘗試下,ok。這就是獲取網(wǎng)絡(luò)請(qǐng)求地址的最常用方法了。 - 類似的,在收集到請(qǐng)求信息后我們嘗試獲取所有簡書熱門專題信息:
from tinydb import TinyDB
db = TinyDB('collection_db.json')
# 這里我們嘗試下tinydb,一句話就獲得了新建的數(shù)據(jù)庫對(duì)象
import csv
csvfile = open("1.csv", "w", encoding='utf-8') # 先保存為utf8編碼,以免出現(xiàn)gbk編碼錯(cuò)誤
fieldnames = ["cname", "href", "focus_number", "essays", "hot_url", "new_url"] # 設(shè)定Excel文件的列表頭
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
# 這里我們獲取csv的字典插入器,可以直接插入字典,鍵為列表頭中的內(nèi)容
writer.writeheader()
# 寫入列表頭
import requests
from bs4 import BeautifulSoup
import re
reg = re.compile('(\d+)篇')
# 使用正則匹配來獲取篇數(shù),(\d+)表示多個(gè)數(shù)字
base_url = "http://jianshu.com"
collectionlist_url = "http://www.itdecent.cn/collections?order_by=score&page=%d"
# collection_url = 'http://www.itdecent.cn/collections/%d/notes?order_by=added_at&page=1'
add_url = 1
# collection_num = 1
collection_selector = "h5 a" # 專題名
focus_on_selector = ".follow > span" # 關(guān)注人數(shù)
total_essay_selector = ".blue-link" # 總篇數(shù)
hot_selector = ".top-articles a" # 熱門排序
new_selector = ".latest-articles a" # 最新收入
total_collection_list = []
while(add_url < 300):
try: # 請(qǐng)求并獲取各種數(shù)據(jù)
first_page = requests.request('get', collectionlist_url% add_url).content
soup = BeautifulSoup(first_page, "lxml")
collection_list = [[i.get_text(),i.get('href')] for i in soup.select(collection_selector)] # 一組24個(gè)
if not collection_list : break
focus_on_list = [i.get_text() for i in soup.select(focus_on_selector)]
focus_on_list = [int(float(i.replace('K', ''))*1000) if ('K' in i) else int(i) for i in focus_on_list]
# 對(duì)尾綴K處理,將K去掉,將數(shù)字乘以1000
total_essay_list =[ int( reg.findall(i.get_text())[0] ) for i in soup.select(total_essay_selector)]
# 使用zip將多個(gè)可迭代對(duì)象合并在一起使用
for c,f,e in zip(collection_list, focus_on_list, total_essay_list):
c.append(f);c.append(e)
second_page = requests.request('get', base_url+c[1]).content
# 訪問專題頁面,獲取該專題的熱門鏈接和最新加入文章頁的鏈接。
soup = BeautifulSoup(second_page, "lxml")
hot_url = soup.select(hot_selector)[0].get('href')
new_url = soup.select(new_selector)[0].get('href')
c += [hot_url, new_url]
for i in collection_list:
#print(add_url, ' ', i)
collection_dict = {"cname": i[0], "href":i[1], "focus_number":i[2], "essays":i[3], "hot_url":i[4], "new_url":i[5]}
db.insert(collection_dict)
# 一句話插入數(shù)據(jù)庫
writer.writerow(collection_dict)
# 寫入csv文件
print(add_url)
add_url += 1
total_collection_list += collection_list
except Exception as e:
print(e)
break
csvfile.close()
# 關(guān)閉文件
- 這里由于編碼問題,直接使用excel打開csv文件會(huì)出現(xiàn)亂碼。我們采取另外一個(gè)簡單方式,直接使用該網(wǎng)站
將之前存入的數(shù)據(jù)庫文件collection_db.json拖入并下載得到我們需要的良好編碼的csv文件。打開結(jié)果如下:
- 以專題關(guān)注人數(shù)排序:
-
以關(guān)注人數(shù)/文章數(shù)比率排序:
- 結(jié)果還是挺有趣的。
- 注意,我們同時(shí)還獲取了各個(gè)專題的熱門和最新加入鏈接。這就是我們一開始爬取的專題鏈接的來源了。
最后輕松一下,完成推薦文章爬取
- 我們來到簡書推薦頁面
http://jianshu.com/recommendations/notes,也就是新上榜,發(fā)現(xiàn)最下有個(gè)button,我們可以使用類似于首頁熱門的爬取方式。代碼基本相似,就不做注釋了。
import requests
from bs4 import BeautifulSoup
base_url = 'http://jianshu.com'
add_url = '/recommendations/notes'
num = 0
while(True):
try:
first_page = requests.request('get', base_url+ add_url).content
soup = BeautifulSoup(first_page, "lxml")
title_list = [i.get_text() for i in soup.select(".title a")]
for i in title_list:
num+=1
print(num, ' ', i)
# print(title_list)
try:
# print(soup.select(".ladda-button"))
add_url = soup.select(".ladda-button")[-1].get("data-url")
except:
break
except Exception as e:
print(e)
break
-
注意,如果直接在windows控制臺(tái)輸出,會(huì)出現(xiàn)編碼錯(cuò)誤,我在Ipython中運(yùn)行,截圖如下:














