1. 程式人生 > 其它 >資料採集與融合技術_實踐2

資料採集與融合技術_實踐2

任務①:

要求:在中國氣象網(http://www.weather.com.cn)給定城市集的7日天氣預報,並儲存在資料庫。

序號 地區 日期 天氣資訊 溫度
1 北京 7日(今天) 晴間多雲,北部山區有陣雨或雷陣雨轉晴轉多雲 31℃/17℃

1.1 實驗步驟

1.1.1 確定url

  • 點進中國氣象網(http://www.weather.com.cn)的連結,選擇一個城市,例如北京,檢視七日天氣預報。

  • 通過檢視網址欄,可以發現url的格式是 ./(某個地區的代號).shtml,如下圖北京的代號為101010100。

  • 在確定其他地區的代號後,我們可以獲得url集

self.cityCode = {"北京": "101010100", "上海": "101020100", "廣州": "101280101", "深圳": "101280601"}
  • 形成完整的url準備進行訪問請求
url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"

1.1.2 urllib傳送請求獲取html

#此處讀取的資料需要使用UnicodeDammit轉換編碼("utf-8", "gbk")
req = urllib.request.Request(url, headers=self.headers)
data = urllib.request.urlopen(req)
data = data.read()

1.1.3 CSS獲取天氣資訊

  • 檢查html

由圖可知,七天的天氣資訊在 ul class="t clearfix"

中的 li 中,通過如下程式碼爬取天氣資訊

lis = soup.select("ul[class='t clearfix'] li")
for li in lis:
    try:
        date = li.select('h1')[0].text #獲取日期的資訊
        weather = li.select('p[class="wea"]')[0].text #獲取天氣的資訊
        temp = li.select('p[class="tem"] span')[0].text + "/" + \
        li.select('p[class="tem"] i')[0].text   #獲取溫度資訊 前者是最高溫,後者是最低溫
        self.db.insert(city, date, weather, temp)  #將資訊插入資料庫
    except Exception as err:
        print(err)

1.1.4 插入資料庫及資料顯示

  • 插入資料庫的函式
def insert(self, city, date, weather, temp):
    try:
        #?是佔位符,代表資料引數
        self.cursor.execute("insert into weathers (wCity,wDate,wWeather,wTemp) values (?,?,?,?)",(city, date, weather, temp))
    except Exception as err:
        print(err)
  • 資料顯示
    獲取所有返回值
#cursor 接收返回值 fetchall()接收全部的返回結果行
rows = self.cursor.fetchall()

資料庫show()函式格式化輸出

rank=1
#chr(12288)中文空格填充
for row in rows:
    print("{0:^5}\t{1:{5}^5}\t{2:{5}^5}\t{3:{5}^5}\t{4:^5}\t".
          format(rank,row[0], row[1], row[2], row[3],chr(12288)))
    rank += 1

結果截圖:

1.1.5 程式碼連結

https://gitee.com/yozhibo/crawl_project/blob/master/task_2/job_1

1.2 實驗心得

1.2.1 收穫

  • 題目給的網址只是主頁的網址,然而需要的資訊並不一定就在主頁中,需要自己去尋找。如本題,不同地區的天氣資訊被放在了不同的url中,提醒了我做題時要更靈活一些。
  • 除了CSS語法的鞏固外,學會了建立class對資料庫進行操作。

1.2.2 問題

  • 在晚上進行爬取時會產生 list index out of range 的錯誤。


    檢查後發現今天的最高溫資訊消失了,所以在select溫度時會產生錯誤,
    但是到了第二天早上再爬取時就會恢復正常。

任務②:

2.1 實驗步驟

2.1.1 獲取url

  • 觀察JS包
    進入除錯模式進行抓包,選擇JS,為了方便查詢,先將捕獲的包全部清除。
  • 可以發現股票的相關資訊儲存在diff中
    並且f與股票的資訊相對應,我們可以通過這個關係進行爬取。但是要注意一下有些引數的值可能是相同的,可以多檢視幾支股票進行判斷。
  • 點選Headers,我們可以看見我們需要的url


  • 同時在下面還有一些其他的引數。

2.1.2 Re正則表示式爬取資訊

  • 各個引數的Re表示式
no = re.findall('"f12":"(.*?)"', str(html))    # 股票程式碼
name = re.findall('"f14":"(.*?)"', str(html))  # 股票名稱
new_price = re.findall('"f2":(.*?),', str(html))  # 最新報價
rate = re.findall('"f3":(.*?),', str(html))    # 漲跌幅
change = re.findall('"f4":(.*?),', str(html))  # 漲跌額
number = re.findall('"f5":(.*?),', str(html))  # 成交量
number_change = re.findall('"f6":(.*?),', str(html))  # 成交額
amp = re.findall('"f7":(.*?),', str(html))    # 振幅
max_ = re.findall('"f15":(.*?),', str(html))  # 最高
min_ = re.findall('"f16":(.*?),', str(html))  # 最低
now = re.findall('"f17":(.*?),', str(html))   # 今開
yes = re.findall('"f18":(.*?),', str(html))   # 昨收

2.1.3 插入函式及資料庫的檢視

  • 插入函式
#插入各列的值,no表示股票程式碼......
def insert(self,no,name,new_price,rate,change,number,number_change,amp,max_,min_,now,yes):
    try:
        self.cursor.execute("insert into shares (股票程式碼,股票名稱,最新報價,漲跌幅,漲跌額,"
                                "成交量,成交額,振幅,最高,最低,今開,昨收) values (?,?,?,?,?,?,?,?,?,?,?,?)",
                                (no,name,new_price,rate,change,number,number_change,amp,max_,min_,now,yes))
    except Exception as err:
        print(err)

  • 使用Database Navigator檢視資料庫,股票程式碼為主碼

2.1.4 程式碼連結

https://gitee.com/yozhibo/crawl_project/blob/master/task_2/job_2

2.2 實驗心得

2.2.1 收穫

  • 修改了第一題的資料庫類,對建立、開啟、關閉資料庫,刪除資料有了更深入的瞭解。查閱了sqlite3、cursor等的相關用法,還有避免因資料庫已存在而報錯的做法。
  • 頁面上的資料不一定是table格式,在原始碼上我們可能搜尋不到想要的資料。此時可以採取抓包的方式,過濾出js檔案並檢視。
  • 學習了使用Database Navigator檢視資料庫,我們可以先執行程式碼生成資料庫,再通過DB Browser連線資料庫檢視裡面的資料。

2.2.2 問題

  • 資料庫插入資料報錯:繫結引數3時 可能不被支援

    經過檢查,這是由於rate是一個列表,而建立資料庫時定義rate是varchar(可變長字串)

    解決方法:將rate改為 rate[i] ,這也是由於不夠仔細而產生的錯誤。

任務③:

要求: 爬取中國大學2021主榜 https://www.shanghairanking.cn/rankings/bcur/2021
所有院校資訊,並存儲在資料庫中,同時將瀏覽器F12除錯分析的過程錄製Gif加入至部落格中。

技巧: 分析該網站的發包情況,分析獲取資料的api

輸出資訊

排名 學校 總分
1 清華大學 969.2

3.1 實驗步驟

3.1.1 除錯分析過程

  • 檢視頭尾鍵值對,高校名,總分,排名,url

3.1.2 正則表達

rank = re.findall(r'ranking:(.*?),rankChange',html,re.S) #獲取排名
name = re.findall(r'univNameCn:"(.*?)"', html, re.S)     #獲取高校名
score = re.findall(r'score:(.*?),', html, re.S)          #獲取總分

3.1.3 資料庫設定

  • 排名的資料型別應該設為 INT 型別,實現按排名進行排序。
self.cursor.execute("create table universities (排名 INT(32),學校 varchar(16),"
             "總分 varchar(16),constraint pk_universities primary key (學校))")

3.1.4 結果展示

3.1.5 程式碼連結

https://gitee.com/yozhibo/crawl_project/blob/master/task_2/job_3

3.2 實驗心得

3.2.1 收穫

  • 對於抓包的過程更加熟練,清晰了url在哪找,html在哪找,其實都是相似的過程,不用感覺很陌生。
  • 第一次碰到這種不顯示真實值,而用字母替代的,不知道為什麼要這樣做,還是挺麻煩的。不過以後碰到類似的情況就有了一點經驗。
  • 再一次體會字串排序和數字排序的差別。

3.2.2 問題

  • 爬取排名時,爬到的並非是數字

查看了JS檔案,發現這可能是一種鍵和值的對應關係,具體的對應關係被藏在了檔案的頭部和尾部。

但這邊只是處理排名的話,就沒有太大必要再去做相關處理。

如果有需要的話,可以用如下正則表示式進行獲取

key = re.findall(r'function\((.*?)\)',html) #獲取鍵
value = re.findall(r'"",(.*?)\)',html)      #獲取值
  • 資料庫的排序問題,如果按照字串的排序,將是1,10,100......
    修改方式位於 3.1.3