C語言中文網 目錄

Python讀取網絡數據(request庫和re模塊)

很多時候,程序并不能直接展示本地文件中的數據,此時需要程序讀取網絡數據,并展示它們。

比如前面介紹的 http://lishi.tianqi.com 站點的數據,它并未提供下載數據的鏈接(前面程序所展示的 csv 文件本身就是使用程序抓取下來的)。在這種情況下,程序完全可以直接解析網絡數據,然后將數據展示出來。

前面已經介紹了 Python 的網絡支持庫 urllib,通過該庫下的 request 模塊可以非常方便地向遠程發送 HTTP 請求,獲取服務器響應。因此,本程序的思路是使用 urllib.request 向 lishi.tianqi.com 發送請求,獲取該網站的響應,然后使用 Python 的 re 模塊來解析服務器響應,從中提取天氣數據。

本程序將會通過網絡讀取 http://lishi.tianqi.com 站點的數據,并展示 2017 年廣州的最高氣溫和最低氣溫。
import re
from datetime import datetime
from datetime import timedelta
from matplotlib import pyplot as plt
from urllib.request import *

# 定義一個函數讀取lishi.tianqi.com的數據
def get_html(city, year, month):  #①
    url = 'http://lishi.tianqi.com/' + city + '/' + str(year) + str(month) + '.html'
    # 創建請求
    request = Request(url)
    # 添加請求頭
    request.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64)' +
        'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36')
    response = urlopen(request)
    # 獲取服務器響應
    return response.read().decode('gbk')

# 定義3個list列表作為展示的數據
dates, highs, lows = [], [], []
city = 'guangzhou'
year = '2017'
months = ['01', '02', '03', '04', '05', '06', '07',
    '08', '09', '10', '11', '12']
prev_day = datetime(2016, 12, 31)
# 循環讀取每個月的天氣數據
for month in months:
    html = get_html(city, year, month)
    # 將html響應拼起來
    text = "".join(html.split())
    # 定義包含天氣信息的div的正則表達式
    patten = re.compile('<divclass="tqtongji2">(.*?)</div><divstyle="clear:both">')
    table = re.findall(patten, text)
    patten1 = re.compile('<ul>(.*?)</ul>')
    uls = re.findall(patten1, table[0])
    for ul in uls:
        # 定義解析天氣信息的正則表達式
        patten2 = re.compile('<li>(.*?)</li>')
        lis = re.findall(patten2, ul)
        # 解析得到日期數據
        d_str = re.findall('>(.*?)</a>', lis[0])[0]
        try:
            # 將日期字符串格式化為日期
            cur_day = datetime.strptime(d_str, '%Y-%m-%d')
            # 解析得到最高氣溫和最低氣溫
            high = int(lis[1])
            low = int(lis[2])
        except ValueError:
            print(cur_day, '數據出現錯誤')
        else:
            # 計算前、后兩天數據的時間差
            diff = cur_day - prev_day
            # 如果前、后兩天數據的時間差不是相差一天,說明數據有問題
            if diff != timedelta(days=1):
                print('%s之前少了%d天的數據' % (cur_day, diff.days - 1))
            dates.append(cur_day)
            highs.append(high)
            lows.append(low)
            prev_day = cur_day
# 配置圖形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 繪制最高氣溫的折線
plt.plot(dates, highs, c='red', label='最高氣溫',
    alpha=0.5, linewidth = 2.0)
# 再繪制一條折線
plt.plot(dates, lows, c='blue', label='最低氣溫',
    alpha=0.5, linewidth = 2.0)
# 為兩個數據的繪圖區域填充顏色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 設置標題
plt.title("廣州%s年最高氣溫和最低氣溫" % year)
# 為兩條坐標軸設置名稱
plt.xlabel("日期")
# 該方法繪制斜著的日期標簽
fig.autofmt_xdate()
plt.ylabel("氣溫(℃)")
# 顯示圖例
plt.legend()
ax = plt.gca()
# 設置右邊坐標軸線的顏色(設置為none表示不顯示)
ax.spines['right'].set_color('none')
# 設置頂部坐標軸線的顏色(設置為none表示不顯示)
ax.spines['top'].set_color('none')
plt.show()
這個程序后半部分的繪圖代碼與前面程序并沒有太大的區別,該程序的最大改變在于前半部分代碼,該程序不再使用 csv 模塊來讀取本地 csv 文件的內容,而是使用 urllib.request 來讀取 lishi.tianqi.com 站點的天氣數據,程序中 ① 號代碼定義了一個 get_html() 函數來讀取指定站點的 HTML 內容。

接下來程序使用循環依次讀取 01~12 每個月的響應頁面,程序讀取到每個響應頁面的 HTML 內容,這份 HTML 頁面內容中包含天氣信息的源代碼如圖 1 所示。


圖 1 包含天氣信息的HTML源代碼

程序中第 32 行代碼使用正則表達式來獲取包含全部天氣信息的 <div.../> 元素,即圖 1 中數字 1 所標識的 <div.../> 元素。

程序中第 34 行代碼使用正則表達式來匹配天氣 <div.../> 中沒有屬性的 <ul.../> 元素,即圖 1 中數字 2 所標識的 <ul.../> 元素。這樣的 <ul.../> 元素有很多個,每個 <ul.../> 元素代表一天的天氣信息,因此,上面程序使用了循環來遍歷每個 <ul.../> 元素。

程序中第 38 行代碼使用正則表達式來匹配每日天氣 <ul...> 中的 <li.../> 元素,即圖 1 中數字 3 所標識的 <li.../> 元素。在每個 <ul.../> 元素內可匹配到 6 個 <li.../> 元素,但程序只獲取日期、最高氣溫和最低氣溫,因此,程序只使用前三個 <li.../> 元素的數據。

通過網絡、正則表達式獲取了數據之后,程序使用 Matplotlib 來展示它們。運行上面程序,即可看到表示 2017 年廣州氣溫變化的數據圖。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo