資料採集與融合技術_實踐2
阿新 • • 發佈:2021-10-16
任務①:
要求:在中國氣象網(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"
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溫度時會產生錯誤,
但是到了第二天早上再爬取時就會恢復正常。
任務②:
- 要求:用requests和自選提取資訊方法定向爬取股票相關資訊。
- 候選網站:東方財富網:http://quote.eastmoney.com/center/gridlist.html#hs_a_board
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