iT邦幫忙

3

Python 爬蟲如何爬須按選項的資料

我找網上爬蟲資料 , 只找到爬固定的網址 , 如果要填選項要怎麼爬如下
像下面天氣資料 , 我要台北市各區半年的資料 , 需要執行按鈕

https://e-service.cwb.gov.tw/HistoryDataQuery/index.jsp

https://ithelp.ithome.com.tw/upload/images/20190901/2011974203YBVPyt26.png

首先要引入下面模組是嗎 ?

from urllib import request
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from urllib.request import urlopen
from urllib.error import HTTPErroe
import re
import sqlite3
from selenium import webdriver
import json
import requests
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
ccutmis
iT邦高手 2 級 ‧ 2019-09-01 09:36:53
最佳解答

學PYTHON爬蟲 要先對網頁運作原理有基本了解
(HTML CSS JAVASCRIPT 網頁表單GET,POST的差別等等)
這些基本的要懂 再來是善用Google Chrome F12大法(不知道請自己去google)
如果你對上述的基本功都有概念了,
就會發現你要的這些資料用不到"需要執行按鈕"這個動作
用requests就可以抓了(資料網頁用到的是網址列帶GET參數)
範例如下:

import requests,time

location_arr=['466910_鞍部','466920_臺北','466930_竹子湖','C0A980_社子','C0A9A0_大直','C0A9B0_石牌','C0A9C0_天母','C0A9E0_士林','C0A9F0_內湖','C0AC40_大屯山','C0AC70_信義','C0AC80_文山','C0AH40_平等','C0AH70_松山','C1AC50_關渡','C1A730_公館','C0A9G0_南港','C0A990_大崙尾山']

date_str="2019-08-06"

#取得單日_單一地點.htm
url="https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s" % (location_arr[0].split("_")[0],date_str)
print(url)
r=requests.get(url)
print("Download: "+date_str+"_"+location_arr[0]+".htm")
with open(date_str+"_"+location_arr[0]+".htm",'w',encoding='utf-8') as f:
	f.write(r.text)
f.close()

#取得單日_全部地點.htm
for i in location_arr:
	url="https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s" %(i.split("_")[0],date_str)
	print(url)
	r=requests.get(url)
	print("Download: "+date_str+"_"+i+".htm")
	with open(date_str+"_"+i+".htm",'w',encoding='utf-8') as f:
		f.write(r.text)
	f.close()
	time.sleep(5)

上列範例會抓單日全部地點(如果要多日全部地點,就把date_str(單日)改成是陣列,再用迴圈去跑)再把抓到的內容存成 "日期_地點.htm",你知道怎麼抓html源碼後,就能用BS4或其它剖析工具去除雜質只留下需要的資料(我個人是偏好用Regular Expression)

沒記錯的話你之前說過現在有在上課,那我會建議你以老師講的為準好好學,例如你可以問他Chrome F12怎麼運用在Python爬蟲上面(若發問是許可的話),遇到哪些情況需要在requests.get時帶header跟form date,如何做等等。

看更多先前的回應...收起先前的回應...
小魚 iT邦大師 1 級 ‧ 2019-09-01 11:36:32 檢舉

竟然是用Get,
不愧是公家機關.
不過就算是POST也是可以用request的.
通常會需要用到按鈕事件的是非同步的.

dragonH iT邦超人 5 級 ‧ 2019-09-01 12:09:34 檢舉

用 get 沒什麼問題吧 /images/emoticon/emoticon13.gif

一般除非是沒辦法直接用 requests 爬

如選項或按鈕是 js render的

才會考慮用 selenium 那類的lib

ccutmis iT邦高手 2 級 ‧ 2019-09-01 16:17:12 檢舉

只要能解決問題的就是好招...
/images/emoticon/emoticon82.gif

kevin543 iT邦新手 5 級 ‧ 2019-09-02 23:41:00 檢舉

請問我加這樣的計算日期迴圈 , 出現錯誤 , 要怎麼除錯


  File "D:/大數據專案/2 (1).py", line 29, in <module>
    print("Download: "+datestring+"_"+location_arr[0]+".htm")

TypeError: can only concatenate str (not "datetime.date") to str
import requests
import datetime as dt  #載入網頁需求與時間

location_arr=['466910_鞍部','466920_臺北','466930_竹子湖','C0A980_社子','C0A9A0_大直','C0A9B0_石牌','C0A9C0_天母','C0A9E0_士林','C0A9F0_內湖','C0AC40_大屯山','C0AC70_信義','C0AC80_文山','C0AH40_平等','C0AH70_松山','C1AC50_關渡','C1A730_公館','C0A9G0_南港','C0A990_大崙尾山']
#將地點存為陣列

#計算半年日期
startdate = dt.datetime(2019, 2,1)
enddate = dt.datetime(2019, 8,1)
totaldate = (enddate - startdate).days + 1

#在for迴圈內作業。
for daynumber in range(totaldate):
    datestring = (startdate + dt.timedelta(days = daynumber)).date()
       

#取得單日_單一地點.htm
url="https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s" % (location_arr[0].split("_")[0],date_str)
#設定網址變數及 split() 通过指定分隔符对字符串进行切片
print(url) # 列印網址
r=requests.get(url) #設定 R 變數為需求網頁
print("Download: "+datestring+"_"+location_arr[0]+".htm")
#列印時間 地點 網頁
with open(datestring+"_"+location_arr[0]+".htm",'w',encoding='utf-8') as f:
#開啟時間地點變更變為 utf-8
	f.write(r.text)
#寫入到為 r.text 檔案
f.close()
#關閉檔案

#取得單日_全部地點.htm
for i in location_arr:
	url="https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s" %(i.split("_")[0],date_str)
	print(url) #列印網頁
	r=requests.get(url) #設定需求網頁變數
	print("Download: "+datestring+"_"+i+".htm") #列印日期迴圈
	with open(datestring+"_"+i+".htm",'w',encoding='utf-8') as f:  
		f.write(r.text)
	f.close()
	time.sleep(5)
ccutmis iT邦高手 2 級 ‧ 2019-09-03 00:19:47 檢舉

會出錯是因為datestring不是字串格式,所以要用str()把它轉成字串,例如:

datestring = (startdate + dt.timedelta(days = daynumber)).date()

改成

datestring = str((startdate + dt.timedelta(days = daynumber)).date())

完整的範例如下:

import datetime as dt  #載入網頁需求與時間
import requests,time

location_arr=['466910_鞍部','466920_臺北','466930_竹子湖','C0A980_社子','C0A9A0_大直','C0A9B0_石牌','C0A9C0_天母','C0A9E0_士林','C0A9F0_內湖','C0AC40_大屯山','C0AC70_信義','C0AC80_文山','C0AH40_平等','C0AH70_松山','C1AC50_關渡','C1A730_公館','C0A9G0_南港','C0A990_大崙尾山']


startdate = dt.datetime(2019, 2,1)
enddate = dt.datetime(2019, 8,1)
totaldate = (enddate - startdate).days + 1

#在for迴圈內作業。
for daynumber in range(totaldate):
	datestring = str((startdate + dt.timedelta(days = daynumber)).date())
	print(datestring)
	#取得單日_全部地點.htm
	for i in location_arr:
		url="https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s" %(i.split("_")[0],datestring)
		print(url)
		r=requests.get(url)
		print("Download: "+datestring+"_"+i+".htm")
		with open(datestring+"_"+i+".htm",'w',encoding='utf-8') as f:
			f.write(r.text)
		f.close()
		time.sleep(5)

上列的範例開始跑的話會跑很久(180”天”x18”地點”x5”秒”=16200"秒"/60/60==大約要4個半小時)才能抓完全部資料。
請小心使用...

kevin543 iT邦新手 5 級 ‧ 2019-09-03 23:07:25 檢舉

感謝你這麼熱心協助 , 請問下面這串網址是怎麼取得的

"https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s"
kevin543 iT邦新手 5 級 ‧ 2019-09-04 09:42:58 檢舉

錯誤訊息 , 是因為網站防爬嗎 ?

ConnectionError: HTTPSConnectionPool(host='e-service.cwb.gov.tw', port=443): Max retries exceeded with url: /HistoryDataQuery/DayDataController.do?command=viewMain&station=466920&stname=&datepicker=2018-01-03 (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x00000180FB5E6278>: Failed to establish a new connection: [WinError 10060] 連線嘗試失敗,因為連線對象有一段時間並未正確回應,或是連線建立失敗,因為連線的主機無法回應。'))
kevin543 iT邦新手 5 級 ‧ 2019-09-04 09:58:02 檢舉

我加這段看看

while 1:
    try:
        page = requests.get(url)
    except:
        print("Connection refused by the server..")
        print("Let me sleep for 5 seconds")
        print("ZZzzzz...")
        time.sleep(5)
        print("Was a nice sleep, now let me continue...")
        continue
ccutmis iT邦高手 2 級 ‧ 2019-09-04 15:10:55 檢舉

HI~我有在你另一篇文章底下回覆了,可以參考一下裡面的寫法,你這個while不太算正解,其實就把time.sleep的值調到10就好,正解是你要有辦法去掌控錯誤時該作什麼,例如記錄下來錯誤的東西,但不要中斷流程...等整個流程跑完,再去把有錯誤的地方補抓即可。

kevin543 iT邦新手 5 級 ‧ 2019-09-04 15:24:34 檢舉

ccutmis 請問這個網址是怎麼來的

"https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s"
ccutmis iT邦高手 2 級 ‧ 2019-09-04 15:40:15 檢舉

那個網址是 http://e-service.cwb.gov.tw/HistoryDataQuery/
點查詢後會跳到這個網址
http://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=466910&stname=%25E9%259E%258D%25E9%2583%25A8&datepicker=2019-09-02
然後你試試把裡面的 datepicker改成2019-08-30 station改成 C0A980 再貼到網址列按enter就會看到它查詢的是 C0A980 點 2019-08-30的資料

所以就可以利用上面已知的部份,把能帶入變數的地方挖掉改成%s
結果如下:

"https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=%s&stname=&datepicker=%s"

這個是格式化字串,用法很簡單,例如:

str1='2019-09-04'
str2='Taipei'
print("Today is %s, Station is %s." %(str1,str2))

print出來的結果是:
Today is 2019-09-04, Station is Taipei.

1
小魚
iT邦大師 1 級 ‧ 2019-09-01 08:14:54

selenium可以.

0
erika
iT邦新手 5 級 ‧ 2019-09-06 09:33:10

其实可以考虑用网页爬虫工具Octoparse。我觉得这样会简单一点。下面是教程鏈接
https://helpcenter.octoparse.com/hc/en-us/articles/360018324051-Can-I-extract-a-table-form-

alex0831 iT邦新手 5 級 ‧ 2020-07-05 00:44:40 檢舉

我是python爬蟲初學者,這個線上教學我看了之後很有幫助,應該可以解決你的問題!

https://www.udemy.com/course/python-crawler/?referralCode=A4F2B9D20A2C35D5001D

我要發表回答

立即登入回答