1. 程式人生 > >【Python爬蟲學習實踐】基於Beautiful Soup的網站解析及數據可視化

【Python爬蟲學習實踐】基於Beautiful Soup的網站解析及數據可視化

為我 enc lambda ech 和我 find weather acc 節點

在上一次的學習實踐中,我們以Tencent職位信息網站為例,介紹了在爬蟲中如何分析待解析的網站結構,同時也說明了利用Xpath和lxml解析網站的一般化流程。在本節的實踐中,我們將以中國天氣網為例,並基於Beautiful Soup庫對其進行數據解析,最後再簡單說明pyecharts數據可視化。

中國天氣網網址:http://www.weather.com.cn/textFC/hb.shtml

技術分享圖片

和之前的Tencent職位信息實踐一樣,我們先來分析一下我們所爬取的網站的結構。在中國天氣網中,我們可以看到其是按照地區進行了分類,如華北、東北、華東、華中等等,並且每一個地區都對應著一個不同的頁面。

接下來我們再來看看我們需要獲取的數據信息。如下圖所示,每一個頁面的數據結構都是以省市為塊的城市數據列表,而這些列表中的數據就是我們需要提取的信息。由於現在當地時間為夜晚,白天的信息也就沒有顯示了,因此在此以爬取夜間的天氣現象和最低氣溫為例,來說明實踐中的Beautiful Soup數據提取的一般化流程。(Ps.註意這裏顯示了一周的天氣情況,而後面的天氣信息都是完整的,後續會介紹如何爬取這些不同天的數據)

技術分享圖片

通過上述簡單分析,我們不難知道其實本次的數據獲取只需要得到相應的URL地址,通過請求獲取其HTML源代碼,再利用解析庫解析出相應的數據即可。下面我們就對此分過程介紹。

Step1——分析天氣URL

從之前的介紹我們知道中國天氣網劃分了幾個不同的地區,每一個地區都對應著一個URL,現在我們就先來看看這些URL的構成法。

華北:http://www.weather.com.cn/textFC/hb.shtml

東北:http://www.weather.com.cn/textFC/db.shtml

華東:http://www.weather.com.cn/textFC/hd.shtml

華中:http://www.weather.com.cn/textFC/hz.shtml

經過觀察分析,發現這幾個URL的域名都是一樣的,只是後面的path的文件名不同,因此我們可以大膽地推測其URL構成法為:’http://www.weather.com.cn/textFC/+{}.shtml’,其中{}為地區名拼音縮寫

接下來,我們再通過其他地區地URL來驗證我們地推測。(十多秒過後…)嗯,結果發現和我們的推測是一樣的,如港澳臺就是引用’gat.shtml’。如此一來,URL的獲取工作就好了。(其實,天氣地區個數較少,網頁URL也比較少,我們也可以手動獲取,不過這樣代碼就會顯得有些冗長)

## 遍歷獲取各地區天氣URL並傳入解析函數

url = http://www.weather.com.cn/textFC/{}.shtml
for flag in (hb, db, hd, hz, hn, xb, xn, gat): parse_page_soup(url.format(flag))

Step2——分析數據信息結構

在獲取了天氣URL後,接下來就要分析我們所需提取的數據結構是怎樣的。下面以華北地區為例,可以看到其省市天氣數據結構如下。發現其數據都放在了一個class為conMidtab的div標簽中,而這樣的標簽共有7個,那麽又分別代表什麽呢?細心觀察後發現只有1個的display 樣式為block,而其他的都是none。其實當我們點擊其他日期的時候,我們會發現其他一個變成了block,而之前的那個變成了none,所以這些其實就是代表不同時間的天氣數據,進入節點查看具體信息後我們也發現這些節點的結構都一樣,也再次說明這就是用來控制顯示不同日期數據的。

技術分享圖片

每一個日期信息的獲取的原理都是一樣的,那麽接下來我們就以北京(今天)為例,進一步分析其數據組織結構。瀏覽源碼我們可以發現在comMidtab的div標簽下有5個comMidtab2的子div標簽,這些其實就是代表華北地區的5個省市,每一個div為一個省市天氣的列表。

技術分享圖片

接下來,在每一個子div中,我們可以找到一個table標簽,而裏面的tbody標簽下又有若幹個tr標簽,掃描後可得知這些tr就是每一個省市數據列表中的行。

技術分享圖片

我們進一步觀察每個tr標簽的內容,可以知道前兩個tr標簽是列表的數據信息頭,而我們真正要獲取的數據為之後的tr標簽。

技術分享圖片

這麽一來,我們便可以結合解析庫來獲取相應的數據信息了。不過在解析的時候要註意一個問題,那就是並不是所有的tr標簽的子結構都是一樣的。如下面的北京和海澱,北京比海澱多了第一個td,從圖中可以看出其實這是旁邊的省市名,因此在解析時需要設定一個好的解析策略。

技術分享圖片

##數據解析
import requests
from bs4 import BeautifulSoup

HEADERS = {
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36,
}

# 設置全局變量,用於保存提取的數據
WEATHER_ALL = []

# 解析數據
def parse_page_soup(url):
    response = requests.get(url, headers=HEADERS)
    text = response.content.decode(utf-8)
    soup = BeautifulSoup(text, html5lib)    #采用html5lib的解析器
    conMidtab = soup.find(div, attrs={class: conMidtab})
    tables = conMidtab.find_all(table)
    for table in tables:
        trs = table.find_all(tr)[2:]        #舍棄前兩個信息頭數據
        for tr in trs:
            tds = tr.find_all(td)
            data = {
                city: list(tds[-8].stripped_strings)[0],    #為統一結構,倒序取值
                weather: list(tds[-4].stripped_strings)[0],
                min_temp: int(list(tds[-2].stripped_strings)[0])
            }
            WEATHER_ALL.append(data)

技術分享圖片

這裏需要說明的是,為什麽我們在解析時采用的時html5lib的解析器呢?其實,采用lxml解析會快很多,但這不安全,因為在本次的天氣網中,並不是所有的天氣頁面都是很規範的。我們可以先試一下用lxml來解析,看看會發生什麽?如下圖,我們發現在解析港澳臺地區的時候發生了錯誤,那麽是為什麽呢?

技術分享圖片

在錯誤中提示列表越界,說明沒有找到對應的標簽,是我們提取出問題了?其實不然,之前在html5lib解析器下都是可以的,說明問題只出在了解析方式上,而這兩種解析器的區別重在容錯性。查看源碼我們發現,港澳臺地區的網頁並不是那麽規範的,在數據表table標簽中,其有前標簽而缺少了尾標簽</table>,也因此容錯性不及html5lib的lxml解析就會出錯,所以我們在寫爬蟲時要先確定好解析器種類,也可使用動態解析器。

技術分享圖片

Step3——數據可視化

在爬取獲得數據後,接下來我們簡單地按照最低氣溫排序並對前12個城市的數據進行可視化處理。

對於排序,因為我們存儲體的是列表對象,可以使用內置的sort()方法,而我們存儲的元素類型為字典結構並對某一屬性值(最低氣溫)排序,因此調用方法時我們需要傳入一個排序關鍵字參數key,並通過lambda表達式使其與字典中的屬性相關聯(這裏也恰好解釋了之前獲取最低氣溫時為什麽要存儲為int類型)。

於可視化處理,我們可以借助一個名為pyecharts的工具庫,使用它可以很方便地繪制各類地數據圖。安裝方法也很簡單,使用pip安裝即可(pip install pyecharts),具體的使用方法在此不在敘述,大家可以參看中文文檔http://pyecharts.org/#/

## 對數據排序並按照最低氣溫取前12個城市制作可視化圖表
from pyecharts import Bar

WEATHER_ALL.sort(key=lambda data: data[min_temp])
data = WEATHER_ALL[0:12]

cities = list(map(lambda x: x[city], data))        #橫軸數據列表
temps = list(map(lambda x: x[min_temp], data))    #縱軸數據列表
chart = Bar("中國天氣最低氣溫排行榜")        #實例化圖表並傳入標題參數
chart.add(‘‘,cities,temps)            #添加一個圖表關系
chart.render(temperature.html)        #繪制並存儲為html文件

技術分享圖片

另外,在安裝pyecharts時顯示安裝成功,然而實際上使用時可能會出現如下的錯誤,提示未找到pyecharts_snapshot模塊,具體解決措施可參看中文文檔(見下圖)技術分享圖片

技術分享圖片


至此,上述便是基於Beautiful Soup庫解析網站的一個實踐,同時也簡單地介紹了數據可視化的內容。其實無論Beautiful Soup還是之前的lxml,解析的一般流程都大致相同,只是適用的環境和解析速度有所區別,在實際的爬取工作中還需要認真分析網頁結構,采取合適的爬取機制和手段。

【Python爬蟲學習實踐】基於Beautiful Soup的網站解析及數據可視化