Board logo

標題: [發問] 關於網頁資料抓取問題 [打印本頁]

作者: sujane0701    時間: 2017-2-5 18:05     標題: 關於網頁資料抓取問題

小弟因職務關係,每日須查詢大量網頁資料(60~100筆,且不斷重覆查詢),並KEY IN成報表,實在太過繁瑣,以前可以利用WEB查詢抓取所須資料,但是現在網頁已無法順利抓取,聽說必須利用到VBA才能完成,因小弟完全不懂VBA,只好厚顏懇請大大幫忙...[attach]26536[/attach]
作者: VBALearner    時間: 2017-2-6 12:28

回復 1# sujane0701

可用Python的Requests與BeautifulSoup模組達成目的,以下影片是範例,可理解後應用
https://www.youtube.com/watch?v=Ef0kh6NPiBE&t=9s
作者: sujane0701    時間: 2017-2-6 19:07

謝謝大大指導,小弟趕快去研究
作者: VBALearner    時間: 2017-2-7 14:49

本帖最後由 VBALearner 於 2017-2-7 14:52 編輯

回復 3# sujane0701

您是個肯學習的人,再幫你一些! 附圖是我用Python3寫的程式所抓出來的資料,這個動作只有查詢主提單的主要資料。更詳細的資料(像是貨品名稱、日期等)要再做第二次訪問動作,就等於是你在主提單查詢頁面上輸入主提單號碼查了第一次,等結果出來後再點擊主提單連結進行第二次訪問搜尋您要的全部資料。
程式須注意的細節 :
1.Requests.Session(),是為了保留登入認證用的Cookie,可以上網Google學習
2.該程式需要兩個非內建的公開模組,安裝完Python3後再自行安裝Requests、BeautifulSoup4模組,安裝方法(ex: Pip install)可上網Google學習
第二次的POST就先留給您試試看,完成的話就可以撰寫成迴圈,以達到重複多次查詢並存取資料的目的! (PS : Time模組目前暫時不須使用,但重複查詢的動作可能會被視為惡意程式,所以未來可能會需要用來減低程式密集的訪問頻率)
[attach]26544[/attach]
作者: sujane0701    時間: 2017-2-7 18:54

本帖最後由 sujane0701 於 2017-2-7 19:02 編輯

謝謝大大,小弟基礎全無,看了四篇網路爬蟲的視頻,產生了許多不明白的地方,雖然已經隱約明白大大指點學習這個的原因,但是有許多名詞及原理有聽沒有懂,後面已經不敢再看下去了,正在到處打聽有沒有相關的基礎書籍,大大是否可以介紹一些入門書籍?
另外請教一點最不明白的地方,請問您現在提供的範例,是excel vba嗎?可以直接在excel類似巨集一樣製作控制鈕之類的是嗎? 我知道問題十分淺薄可笑,可是小弟實在不懂,請大大不吝撥空指導~
作者: sujane0701    時間: 2017-2-7 19:11

懂了懂了!看完第五,六篇介紹,知道Python3可以將訪問結果轉成excel,形成一個類似資料庫來源的檔案,方便製作報表,前面問的笨蛋問題,請大大不要理我.....
作者: VBALearner    時間: 2017-2-8 12:17

回復 6# sujane0701

Python跟VBA是兩種不同的語言,VBA比較像是EXCEL專屬的物件語言,所以VBA在處理非EXCEL內建功能的問題上就有許多不足,但也因為功能都focus在EXCEL上,也比其他語言好學許多,認真學的話,一個月不到就可以學完9成的語法+應用。我一開始也是從VBA學起,想當初還耍任性求版大幫我升級xD,後來發現Python在抓網路資料更快、更方便的時候,我就移情別戀了,有關VBA去POST網頁的程式我比較不熟,這可能要問VBA高手們比較合適 : GBKEE、c_c_lai、准提布林...
作者: VBALearner    時間: 2017-2-8 12:41

回復 6# sujane0701

對了,要"爬蟲"要學會看懂網頁原始碼(HTML)喔
作者: koshi0413    時間: 2017-2-8 22:38

回復 1# sujane0701

建議泥把VBA大大給的影片,大數據學堂相關的前十個影片全看完
基本的就會了,小弟爬虫的知識全是靠這網站的影片指導的
其它的請用GOOGLE泥自己要的功能,就會有範例了,不過大多為簡體字
先給泥這簡易說明的網址看看
http://www.runoob.com/python/python-100-examples.html

PS:因為泥是要抓進XLS,有直接可以存成XLS的套件  OR  另存成 TXT CSV 皆可

python這套對於網抓來說,簡單是簡單,但還是要花費一些時間去了解的,所以多試試吧
先試出能提取一筆存在xls之後,在用迴圈來逐一用主提單號碼提取資料就方便許多了
如果真的資料量太大的話,到時在去研究 sqlite3套件來配合xls即可,只不過又要多學習 sql 語法
作者: sujane0701    時間: 2017-2-8 23:22

感謝VBALearner及 koshi0413 兩位耐心,看過視頻後突然發現眼界大開,很希望學會抓取網路資料的技術,昨天特地去買了一本網頁設計入門,期望在工作之餘打一點基礎,再次謝謝2位大大指明學習方向,非常感謝~
作者: VBALearner    時間: 2017-2-9 11:35

回復 10# sujane0701

爬蟲的知識要靠自己一點一滴慢慢去天天摸,天天累積,最重要的是,遇到問題要能在"GOOGLE搜尋"找答案,前人所累積的知識都存在於網路這個大資料庫裡,小弟我也是站在巨人的肩膀上學習。等您大概看懂HTML的主要標籤(常用的就好,不要鉅細靡遺的背),並能夠理解如何用Python、Chrome的開發人員工具實現POST動作後,您就可以改我的程式碼去做第二次POST動作,獲取您最終要的資料了,再配合xls套件把資料存檔即可。以下附圖提示第二次POST的參數所在位置,有關Python不懂的語法GOOGLE一下即可得知,有問題歡迎再提出,加油!!!
[attach]26576[/attach]
作者: VBALearner    時間: 2017-2-9 11:42

回復 10# sujane0701

第二次POST所需參數如圖,用Chrome的開發人員工具觀察即可得知POST的所需資訊
[attach]26577[/attach]
作者: VBALearner    時間: 2017-2-9 15:40

回復 12# VBALearner

發現少框兩個參數...
其實可以不用POST方法,用原始碼給的已附加參數的網址GET也可以
作者: c_c_lai    時間: 2017-2-9 19:52

本帖最後由 c_c_lai 於 2017-2-9 19:59 編輯

回復 11# VBALearner
請教為何會無 select 屬性?
[attach]26585[/attach]
我輸入內容是否有誤?
  1. import requests
  2. import time
  3. from bs4 import BeautifulSoup
  4. 主提單號碼=['160-69306532','608-10318674']

  5. with requests.session() as r:
  6.     res = r.get('https://accs.tradevan.com.tw/accsw-bin/APACCS/userLoginAction.do?userid=GUEST&password=GUEST')
  7.     for code in 主提單號碼:
  8.         print('主提單號碼:',code, '\n')
  9.         payload = {'mawb_no':code,'查詢':'查詢'}
  10.         res = r.post("https://accs.tradevan.com.tw/accsw-bin/APACCS/clmMergeQueryAction.do", data=payload)
  11.         res.encoding = "big-5"
  12.         html = BeautifulSoup(res.text,"html.parser")
  13.         for tr in html.body.select('table')[4].select('tr')[1:]:  #請詳閱w3school裡有關HTML的Table標籤知識,就能知道這裡在做啥
  14.             data = []  #建立陣列
  15.             for td in tr.select('td'):
  16.                 data.append(td.text.strip())
  17.                 if td == tr.select('td')[len(tr.select('td'))-1]: #這裡有下一個POST所需的資訊 (payload),透過觀察網頁原始碼得知
  18.                     print('第二次POST的資料:',td,'\n')
  19.             print('摘要資訊:',data, '\n')   #第一次查詢得到的摘要資料
複製代碼

作者: VBALearner    時間: 2017-2-9 23:04

回復 14# c_c_lai

c大,不好意思,這是我的錯xD
我沒有PO程式碼造成您的手動輸入錯誤...真是抱歉哈哈哈
魔鬼藏在網址的細節裡哈哈哈
[attach]26587[/attach]
Hint : I跟L還真像阿呵呵
作者: c_c_lai    時間: 2017-2-10 04:58

回復 15# VBALearner
加了 #,排除 Select,接下來是索引範圍了!
[attach]26588[/attach]
作者: VBALearner    時間: 2017-2-10 12:13

回復 16# c_c_lai

我發現昨天PO圖時打錯了網址的順序了,我把你的打成我的...正確是"大寫i"才對......= ="
附原始碼,希望可以一勞永逸解決這問題 ...
  1. import requests
  2. import time
  3. from bs4 import BeautifulSoup

  4. 主提單號碼 = ['160-69306532','608-10318674']

  5. with requests.session() as r:
  6.     res = r.get('https://accs.tradevan.com.tw/accsw-bin/APACCS/userLoginAction.do?userid=GUEST&password=GUEST')
  7.     for code in 主提單號碼:
  8.         print('主提單號碼 :',code,'\n')
  9.         payload = {'mawb_no':code,'查詢':'查詢'}
  10.         res = r.post("https://accs.tradevan.com.tw/accsw-bin/APACCS/cImMergeQueryAction.do", data=payload)
  11.         res.encoding = "big-5"
  12.         html = BeautifulSoup(res.text,"html.parser")
  13.         for tr in html.body.select('table')[4].select('tr')[1:]: #請詳閱w3school裡有關HTML的Table標籤知識,就能知道這裡在做啥
  14.             data = [] #建立陣列
  15.             for td in tr.select('td'):
  16.                 data.append(td.text.strip())
  17.                 if td == tr.select('td')[len(tr.select('td'))-1]: #這裡有下一個POST所需的資訊(payload),透過觀察網頁原始碼得知
  18.                     print('第二次POST的資料 :',td,'\n')
  19.             print('摘要資訊 :',data,'\n') #第一次查詢得到的摘要資料
複製代碼

作者: sujane0701    時間: 2017-2-10 13:01

主提單號碼 = ['160-69306532','608-10318674']
請問,如果想要指向某一個EXCEL檔案第一個工作表A2儲存格,隨著A2變化而取得不同的主號資料,可以這麼做嗎?應該如何更改呢?
作者: VBALearner    時間: 2017-2-10 14:17

回復 18# sujane0701

Python有關Excel的操作有很多方式,xlrd模組是其中一種
[attach]26590[/attach]
作者: c_c_lai    時間: 2017-2-10 17:41

回復 17# VBALearner
太棒了!謝謝你!
[attach]26591[/attach]
作者: VBALearner    時間: 2017-2-10 21:22

本帖最後由 VBALearner 於 2017-2-10 21:24 編輯

回復 18# sujane0701
回復 20# c_c_lai

應C大的期待,加入第二次POST,完稿。
想當初C大也回應我許多VBA的低能問題xD,記得當時我PO了一篇分享文"三大法人買賣超資料整理...",結果就有高手用Python把自動下載Excel的程式碼貼出來,引發幾十頁的熱烈討論。若不是高手無私分享、令我對Python語言大開眼界並產生高度興趣的話,我便不會去學習Py,可能還停留在VBA吧... 因此,完整的程式碼S大、C大請享用,並鼓勵Py高手對我的程式碼提出建言,S大您接下來只需要把資料存成Excel,這一步很簡單,網路找找吧,加油。
  1. import requests
  2. import time
  3. from bs4 import BeautifulSoup

  4. postfreq = 0.8 #避免過度頻繁的訪問被當成惡意程式攻擊(類似小型DDOS),秒數間隔訪問是爬蟲的基本禮貌

  5. #僅以兩筆主提單號碼示範,欲增加自行更改即可
  6. 主提單號碼 = ['160-69306532','608-10318674'] #,'851-26325773','479-32003532','695-08802916','297-64647785']

  7. with requests.session() as r:
  8.     res = r.get('https://accs.tradevan.com.tw/accsw-bin/APACCS/userLoginAction.do?userid=GUEST&password=GUEST')
  9.     for code in 主提單號碼:
  10.         print('主提單號碼 :',code,'\n')
  11.         time.sleep(postfreq)
  12.         payload = {'mawb_no':code,'查詢':'查詢'}
  13.         res = r.post("https://accs.tradevan.com.tw/accsw-bin/APACCS/cImMergeQueryAction.do", data=payload) #第一次訪問
  14.         res.encoding = "big-5"
  15.         html = BeautifulSoup(res.text,"html.parser")
  16.         num = 1
  17.         for tr in html.body.select('table')[4].select('tr')[1:]: #把Table裡的tr資料逐列取出
  18.             summary = [] #建立摘要資訊的存放陣列
  19.             postdata = [] #二次訪問所需參數的存放陣列
  20.             for td in tr.select('td'):
  21.                 summary.append(td.text.strip())
  22.                 if td == tr.select('td')[len(tr.select('td'))-1]: #這裡有下一個POST所需的資訊(參數),透過觀察網頁原始碼得知
  23.                     postdata.append(str(td).split('&')[1].replace('flight_no=','')) #參數1
  24.                     postdata.append(str(td).split('&')[2].replace('flight_date=','')) #參數2
  25.                     postdata.append(str(td).split('&')[3].replace('est_arrival_date=','')) #參數3
  26.    
  27.             print('  ','摘要資訊'+str(num),':',summary,'\n') #第一次查詢得到的摘要資料
  28.             num+=1

  29.             payload = {'mawb_no':code,
  30.                        'voyage_flight_no':postdata[0],
  31.                        'est_arrival_date':postdata[2],
  32.                        'flight_date':postdata[1],
  33.                        'qry_mawb_no':code,
  34.                        'qry_sort':'0'
  35.                        }
  36.             time.sleep(postfreq)
  37.             res = r.post("https://accs.tradevan.com.tw/accsw-bin/APACCS/cImMergeListAction.do", data=payload) #第二次POST
  38.             res.encoding = "big-5"
  39.             html = BeautifulSoup(res.text,"html.parser")

  40.             print('  ','詳細資料如下 :')
  41.             for tr in html.select('table')[4].select('tr'):
  42.                 data = []
  43.                 for td in tr.select('td'):
  44.                     data.append(td.text.replace('\r','').replace('\n','').replace(' ','').strip())
  45.                 print('\t',data)
  46.             print('\n')
  47.             #運用其他模組把爬到的資料存成Excel即大功告成,甚至可以進一步運用select語法篩選特定位置的資料
複製代碼
[attach]26593[/attach]
作者: c_c_lai    時間: 2017-2-10 21:43

回復 21# VBALearner
蠻不錯的詮釋!
謝謝囉!
作者: sujane0701    時間: 2017-2-13 13:24

呵,小弟太差勁了,VBALearner大即使公佈答案,小弟暫時還是一知半解,先收下VBALearner大的大禮包好好研究,非常感謝!
作者: VBALearner    時間: 2017-2-13 21:22

本帖最後由 VBALearner 於 2017-2-13 21:25 編輯

回復 23# sujane0701

沒關係,我只希望幫助願意學習而不是只伸手討免費程式的人。
您是個被程式威力激發熱情的人,跟小弟我一樣,小弟我一年前連一句程式碼都不會寫,希望您保持這份熱情持續學習。
您若只要部分資料,可以透過更改以下我PO的三句語法,去一一挑出要存取的資料位置。例如: html.select('table')[4].select('tr')[2].select('td')[1] 可以挑出表格中第三列從左數來第二個資料點,也就是"貨棧"的資料點,然後一一輸入進陣列後,再一併寫入Excel即可完成你的目標,工作順利 !
  1.             for tr in html.select('table')[4].select('tr'):
  2.                 data = []
  3.                 for td in tr.select('td'):
複製代碼
  1. data = []
  2. data.append(html.select('table')[4].select('tr')[2].select('td')[1])
  3. data.append(html.select('table')[4].select('tr')[?].select('td')[?])

  4. with open("xxx.xlsx",xx) as excel:
  5.     #寫入的程式碼
複製代碼

作者: stillfish00    時間: 2017-2-15 20:03

回復 23# sujane0701
Python 絕對是值得學習的語言,較熱門,套件也多。
參考 VBALearner 的 code ,改為 VBA 的 code 應該也是能達到你的需求的:
  1. Sub 查詢()
  2.     Dim oXmlhttp: Set oXmlhttp = CreateObject("msxml2.xmlhttp")
  3.     Dim oHtml: Set oHtml = CreateObject("htmlfile")
  4.     Dim sUrl As String, sPost As String, sID As String
  5.     Dim ar, r, i, j
  6.    
  7.     With Sheets(1)
  8.         ar = .[a1].Resize(.Cells(.Rows.Count, 1).End(xlUp).Row)
  9.     End With
  10.     For r = 2 To UBound(ar)
  11.         sID = ar(r, 1)
  12.         With oXmlhttp
  13.             sUrl = "https://accs.tradevan.com.tw/accsw-bin/APACCS/userLoginAction.do?userid=GUEST&password=GUEST"
  14.             .Open "Get", sUrl, False
  15.             .send
  16.             oHtml.Body.innerhtml = .responsetext
  17.             sUrl = "https://accs.tradevan.com.tw/accsw-bin/APACCS/cImMergeQueryAction.do"
  18.             sPost = "mawb_no=" & sID & "&查詢=查詢"
  19.             sPost = oHtml.parentWindow.encodeURI(sPost)
  20.             .Open "Post", sUrl, False
  21.             .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  22.             .setRequestHeader "Content-Length", Len(sPost)
  23.             .send (sPost)
  24.             oHtml.Body.innerhtml = .responsetext
  25.             With oHtml.GetElementsByTagName("table")(4).Rows(1)
  26.                 sInfo = .Cells(.Cells.Length - 1).GetElementsByTagName("a")(0).href
  27.             End With
  28.             
  29.             sUrl = "https://accs.tradevan.com.tw/accsw-bin/APACCS/cImMergeListAction.do"
  30.             sPost = "mawb_no=" & sID & _
  31.                         "&voyage_flight_no=" & Split(Split(sInfo, "flight_no=")(1), "&")(0) & _
  32.                         "&flight_date=" & Split(Split(sInfo, "flight_date=")(1), "&")(0) & _
  33.                         "&est_arrival_date=" & Split(Split(sInfo, "est_arrival_date=")(1), "&")(0) & _
  34.                         "&qry_mawb_no=" & sID & _
  35.                         "&qry_sort=0"
  36.             sPost = oHtml.parentWindow.encodeURI(sPost)
  37.             .Open "Post", sUrl, False
  38.             .setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
  39.             .setRequestHeader "Content-Length", Len(sPost)
  40.             .send (sPost)
  41.             oHtml.Body.innerhtml = .responsetext
  42.             With oHtml.GetElementsByTagName("table")(4)
  43.                 For i = 0 To .Rows.Length - 1
  44.                     With .Rows(i)
  45.                         For j = 0 To .Cells.Length - 1
  46.                             Sheets(2).Cells((r - 2) * 12 + i + 1, j + 1).Value = .Cells(j).innertext
  47.                         Next
  48.                     End With
  49.                 Next
  50.             End With
  51.         End With
  52.     Next
  53. End Sub
複製代碼

作者: VBALearner    時間: 2017-2-17 20:23

回復 25# stillfish00

挖靠 VBA專家無誤
有關VBA的爬蟲程式似乎極為少見,敢問fish大是在哪裡學VBA爬蟲的語法呢?
作者: stillfish00    時間: 2017-2-20 13:55

回復 26# VBALearner
網路自學的,對岸論壇有不錯的資料
http://club.excelhome.net/thread-1303169-1-1.html
作者: VBALearner    時間: 2017-2-23 01:10

回復 27# stillfish00

感謝您! 我有空來研究研究,順便複習VBA,Py寫久了都忘記怎麼寫VBA了= ="




歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)