上一篇《Python 網路爬蟲實戰:爬取人民日報新聞文章》發布之后,確實幫到了不少朋友,
前幾天,我好哥們問我:我想爬另一個日報新聞網站,網頁結構幾乎跟人民日報幾乎一模一樣,但是我用你的那個代碼去爬卻爬不下來資料呢?
順著哥兒們發來的網址(網站傳送地址:解放日報),我點進去看了一下,界面大概長這樣,

跟人民日報的主頁界面非常相似,都是 版面串列 -- 文章串列 -- 文章詳情 的這種結構,

本來我覺得肯定是我這哥兒們代碼基礎不過關,報的語法錯誤,先 “嘲諷” 他一波,然后幫他改好就得了,
沒想到一分析,才發現這個網站的新聞資料,是 Ajax 動態加載出來的(具體區別就是,人民日報的資料是提前生成好在網頁里,跟網頁一起回傳顯示的;而解放日報則是分開的,先回傳一個空網頁,然后再通過資料的介面請求資料,把資料動態加載到空網頁里顯示)
雖然這個動態加載的爬蟲也并不難,花了十來分鐘就改完了,但是我感覺這還是蠻典型的一種型別的,所以趁這個機會拿來跟大家分享一下,遇到了這種類似的情況應該怎么做,
一、分析網站
其實第一步應該是 明確需求 的,就是要明確我們需要什么樣的資料,希望以什么樣的形式才保存等等,不過由于我們這個跟《人民日報》爬蟲目標一致,所以需求部分就暫且略過了,
我們直接來分析網站,
1.1 資料動態加載是怎么回事兒
很多剛接觸爬蟲的同學,上來 F12 打開開發者工具,就咔咔定位資料找標簽,如果是像人民日報那樣的靜態網頁還好,你分析時看到的標簽是什么樣子,用代碼爬的時候基本上也是那個樣子;但是遇到解放日報這種動態加載的網站,就直接懵逼了,明明我標簽位置,名字,class 和 id 什么的都沒寫錯,為什么爬取的時候就總是報錯說找不到標簽呢?
答案就是,你找的那個標簽是動態生成的,原始網頁原始碼里根本沒有,當然找不到了,
大家看下面,這是解放日報的版面導航串列,

一般大家爬取的時候,會先找到這個 <div class="dd-box"> 標簽,然后在這個標簽下找到所有的 <dd> 標簽,然后再找 <a> 標簽,然后就找到了想要的資料,
然鵝,當我們打開查看網頁原始碼的時候(chrome 瀏覽器為例,滑鼠右鍵,查看網頁源代碼),發現源代碼里并沒有我們需要的資料,而是一個類似于模板的東西,資料是通過后續動態的加載進來的,

當我們用爬蟲去爬的時候,獲取到的也是這樣的源代碼,當然取不到資料啦,
Tips1: 分析網頁的時候,可以先查看一下網頁源代碼,看看自己需要的資料是否在里面,如果有,則可以繼續接著分析,如果沒有,說明資料是動態加載進來的,要換個思路,
1.2 資料是怎么獲取到的
既然網頁源代碼中找不到資料,那么我們去哪兒獲得資料呢?
這就涉及到一個詞,叫 “抓包” ,可能聽上去很高深很難的樣子,其實很簡單的,我們知道資料肯定是通過發起 網路請求 獲得的,就是網頁向服務器發送一條請求,然后服務器把需要的資料回復回來,我們把網頁向服務器發送的請求,和瀏覽器回傳的資料,使用一些工具和手段截獲下來進行分析,這個程序就是 “抓包”,
可能大家聽著還是有點迷糊,下面我來具體演示一下,
打開開發者工具,切換到 Network,然后重繪網頁(這里可以抓到網頁加載程序中,向服務器發起的各種型別的請求),

然后上圖紅框中圈出來的,就是我們抓取到的一條一條的請求包,有 js 腳本的,有 css 檔案的,還有圖片的等等各種型別的,我們要在這么多的 “請求包” 里找到包含我們需要的資料的包,
把串列里的這些請求從上到下一條一條的點開(在 Preview 里可以預覽請求回傳的資料),查看哪條請求是我們想要找的,

如上圖箭頭標識的請求點開以后,預覽里的內容正好就是版面導航欄里的內容(預覽里點擊小箭頭可以展開),我們成功找到了正確的請求,
也就是抓包成功!
1.3 抓到的包怎么用?
包含資料的請求包我們是抓到了,但是我們具體要怎么用呢?怎么把它用到爬蟲程式里,通過它來爬資料呢?
還是那條請求,我們切換到 Headers 頁簽,可以查看到關于這條請求的一些基本資訊,

主要關注幾個部分 Request URL(請求鏈接),Request Method(請求方法),Query String Parameters(請求引數),(當然請求頭的那些東西,User-Agent ,Cookie 什么的,按照實際情況該怎么加就怎么加),
我們的目的就是,通過 python 代碼模擬瀏覽器發出這條請求,直接獲取服務器回傳的資料(回傳的資料就是前面預覽里的那些),
import requests
url = "https://www.shobserver.com/staticsg/data/journal/2021-04-24/navi.json?ver=1619268138175"
r = requests.get(url)
print(r.text)
我們簡單寫幾行代碼模擬一下這個程序(url 就是上圖中 Request URL 的內容,requests.get() 是因為 Request Method 是 GET),
運行結果如下,可以成功獲得資料,

1.4 怎么爬其他日期的資料
運行上面的代碼,我們可以獲得到 2021 年 4 月 24日的新聞資料,那我們如果想爬其他日期的新聞資料該怎么辦呢?
這里我們觀察一下請求的 url
https://www.shobserver.com/staticsg/data/journal/2021-04-24/navi.json?ver=1619268138175
其中有一段 2021-04-24 的字樣,我們猜測,這個可能就是用來控制獲取資料的日期的,改成別的日期 比如 2021-04-20 再試一下,
https://www.shobserver.com/staticsg/data/journal/2021-04-20/navi.json?ver=1619268138175
發現同樣可以成功,
這樣我們就知道,可以通過修改 url 里的日期字串,來爬取指定日期的資料,
1.5 決議資料
該請求回傳的資料,是 json 格式的字串,我們需要用 json 庫來進行決議,
(有同學可能想問了,那么一大串亂碼似的文字,你怎么知道它是 json 格式的呢?簡單來講,看兩個特點,一個是大括號 {} 包起來的,另一個是鍵值對格式,就是 xxx : xxx 這種形式的,實在不知道怎么判斷的話,就去前面講抓包的部分,看預覽的地方,如果有小箭頭能夠折疊展開的,就是 json 格式)

我們可以看到 pages 里有版面的串列,每個版面的 articleList 里有文章串列,包含了我們需要的版面和文章串列資訊,具體決議的 Python 代碼這里就不講了,文末會貼原始碼,
1.6 怎么爬文章詳細內容
首先點開一個文章的正文頁,用前面同樣的分析方法過一遍,很容易知道,正文內容也是動態加載進來的,而且正文的資料是通過下面這條請求來獲得到的,

我們簡單寫段代碼來驗證一下
import requests
url = "https://www.shobserver.com/staticsg/data/journal/2021-04-24/01/article/312840.json?ver=1619271661571"
r = requests.get(url)
print(r.text)
運行結果

經過對這條請求的 url 的分析,我們可以知道,/2021-04-24 是日期,/01 是指版面的編號,/312840 是文章的id,
https://www.shobserver.com/staticsg/data/journal/2021-04-24/01/article/312840.json?ver=1619271661571
至此,我們完成了對網站的分析,講解了如何判斷網站資料是動態加載還是靜態加載,如果是動態加載的話如何抓包,抓包以后如何使用等等,并抓到了 新聞版面串列,文章串列,文章正文內容的請求介面,如果有哪里沒有講清楚,或者對以上內容有不太明白的地方,可以留言問我,
下面進行寫代碼,正式爬取,
二、編碼環節
下面是爬蟲原始碼,供大家學習交流使用,請勿用于非法用途,
import requests
import bs4
import os
import datetime
import time
import json
def fetchUrl(url):
'''
功能:訪問 url 的網頁,獲取網頁內容并回傳
引數:目標網頁的 url
回傳:目標網頁的 html 內容
'''
headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
}
r = requests.get(url, headers=headers)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
def saveFile(content, path, filename):
'''
功能:將文章內容 content 保存到本地檔案中
引數:要保存的內容,路徑,檔案名
'''
# 如果沒有該檔案夾,則自動生成
if not os.path.exists(path):
os.makedirs(path)
# 保存檔案
with open(path + filename, 'w', encoding='utf-8') as f:
f.write(content)
def download_jfrb(year, month, day, destdir):
'''
功能:網站 某年 某月 某日 的新聞內容,并保存在 指定目錄下
引數:年,月,日,檔案保存的根目錄
'''
url = 'https://www.shobserver.com/staticsg/data/journal/' + year + '-' + month + '-' + day + '/navi.json'
html = fetchUrl(url)
jsonObj = json.loads(html)
for page in jsonObj["pages"]:
pageName = page["pname"]
pageNo = page["pnumber"]
print(pageNo, pageName)
for article in page["articleList"]:
title = article["title"]
subtitle = article["subtitle"]
pid = article["id"]
url = "https://www.shobserver.com/staticsg/data/journal/" + year + '-' + month + '-' + day + "/" + str(pageNo) + "/article/" + str(pid) + ".json"
print(pid, title, subtitle)
html = fetchUrl(url)
cont = json.loads(html)["article"]["content"]
bsobj = bs4.BeautifulSoup(cont, 'html.parser')
content = title + subtitle + bsobj.text
print(content)
path = destdir + '/' + year + month + day + '/' + str(pageNo) + " " + pageName + "/"
fileName = year + month + day + '-' + pageNo + '-' + str(pid) + "-" + title + '.txt'
saveFile(content, path, fileName)
if __name__ == '__main__':
'''
主函式:程式入口
'''
# 爬取指定日期的新聞
newsDate = input('請輸入要爬取的日期(格式如 20210416 ):')
year = newsDate[0:4]
month = newsDate[4:6]
day = newsDate[6:8]
download_jfrb(year, month, day, 'Data')
print("爬取完成:" + year + month + day)
以上是爬取單天的新聞文章的爬蟲,如果希望爬取一段時間內的新聞文章資料,可以參照《Python 網路爬蟲實戰:爬取人民日報新聞文章》中的代碼進行修改,
三、運行效果
運行程式,輸入 20210424 以后,爬蟲自動爬取了 2021年4月24日的新聞資料,并保存在 Data / 20210424 / 目錄下,
如果文章中有哪里沒有講明白,或者講解有誤的地方,歡迎在評論區批評指正,或者掃描下面的二維碼,加我微信,大家一起學習交流,共同進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/280364.html
標籤:python
上一篇:Two Sum
下一篇:Python(七)之郵件處理
