返回列表 上一主題 發帖

[原創] python上市櫃三大法人買賣超日報資料下載

前幾天c大回覆的時候有貼了vba的code,讓我想到如果找一些在excel版的問題用python試做看看,也許有興趣的朋友可以相互參照。
抓資料很多問題想起來不困難,但像我都只做簡單的應用,經驗有限,真要做比較完整的資料爬取,撞牆的細節問題想必非常多。
最近比較有時間,剛好趁這個機會練習一下。歡迎版上的朋友一起研究討論,如果有其他使用python的前輩,也請不吝給我一些提點跟建議。
一開始我想就從這篇開始http://forum.twbts.com/thread-18259-1-2.html
GBKEE版大已經用vba提供了很好的解決方案,但若是想換個口味還是可以用python試試看把資料爬取下來。

網址網址:http://church.oursweb.net/slocation.php?w=1&c=TW&a=&t=&p=
Screenshot_1.png
2016-9-10 21:08

網頁看起來沒有什麼奇奇怪怪的javascript,如果只是要抓圖片中的簡易資料,那只要:
  1. #準備工具
  2. import requests
  3. from bs4 import BeautifulSoup

  4. #建立一個session
  5. s = requests.session()

  6. for i in range(11,14):
  7.     #網址變動的只有最後一個數字,共286頁,用range(1,287)就可以把所有數字跑過一次
  8.     #測試時請不要跑太多頁,用(1,3)、(11,14)、(280,283)之類的就好
  9.     url = 'http://church.oursweb.net/slocation.php?w=1&c=TW&a=&t=&p=' + str(i)
  10.     res = s.get(url)
  11.     #若收到的res文字為亂碼就加個encoding
  12.     res.encoding = 'utf-8'
  13.     soup = BeautifulSoup(res.text, 'lxml')
  14.         
  15.     #取得資料,我們要的資料都存在這兩種tr裡   
  16.     data = soup.find_all('tr',['tb__a', 'tb__b'])

  17.     #將資料印出
  18.     for d in data:
  19.         print(d.text)
  20.         
  21.     i += 1
複製代碼
那如果要收集詳細資料呢?那就要取得每頁裡的各個教會的連結,一個一個進去爬取。

TOP

回復 61# zyzzyva
請教 print(d.text) 它會從哪裡顯示結果?
我按了 Shift Enter 後即石沉大海,謝謝你!

TOP

本帖最後由 zyzzyva 於 2016-9-11 08:06 編輯

回復 62# c_c_lai
石沉大海...因為真的沒有資料XD
不知道為啥程式碼貼上的時候論壇系統會修改,下面這段
data = soup.find_all('tr',['tb__a', 'tb__b']),應該是
Screenshot_2.png
2016-9-11 08:05

修改一下應該就正常了。

TOP

回復 63# zyzzyva
感謝! 終於石榴開花了!
新增派工.png
2016-9-11 08:22

速度非常快, 再來多個好範例學習學習。
謝謝囉!

TOP

本帖最後由 zyzzyva 於 2016-9-11 08:45 編輯

到這邊離GBKEE版大爬到的詳細資料還有相當距離。
我們的下一步應該是要取得頁面中各教會的連結:
  1. import requests
  2. from bs4 import BeautifulSoup

  3. s = requests.session()

  4. for i in range(11,13):
  5.     url = 'http://church.oursweb.net/slocation.php?w=1&c=TW&a=&t=&p=' + str(i)
  6.     res = s.get(url)
  7.     res.encoding = 'utf-8'
  8.     soup = BeautifulSoup(res.text, 'lxml')

  9. #--------下面改成這樣以取出頁面中各教會的連結
  10.     for d in soup.select('a[href^="church.php?pkey"]'):
  11.             myUrl = 'http://church.oursweb.net/' + d.get('href')
  12.             print(myUrl)    #先把連結印出來測試一下
  13.             #get_detail(myUrl,s) 之後用個function處理頁面中的資料
  14.     i += 1
複製代碼
再來就是要弄個function,看了一下網頁,這裡應該是比較麻煩的地方。

TOP

回復 64# c_c_lai
這個我會做比較完整的,目標是像GBKEE版大抓下來的各教會的詳細資料。

TOP

回復 66# zyzzyva
新增派工.png
2016-9-11 08:56

靜觀其變,先謝謝囉!
其實我個人也蠻希望如此窮追不捨地去尋根。

TOP

本帖最後由 zyzzyva 於 2016-9-11 10:41 編輯

因為最後希望能輸出到csv(準備使用csv module的dictwriter,以key:value的方式寫入),所以要先把資料處理好。
試著直接把資料印出來
Screenshot_1.png
2016-9-11 10:02

好像還可以。那試著把資料放到list裡看看
Screenshot_2.png
2016-9-11 10:03

還真是醜,應該是因為全部的資料都在同一個td裡,中間又有空白、換行,實在不知道從何處理起。
Screenshot_3.png
2016-9-11 10:13

換個方式先把字串取出來,順便把空白去掉,看起來好多了,是我能夠處理的資料了。
(這樣要多一個list,感覺有點繞路,應該有更好的處理方式,不過暫時沒想出來,先能work再說)
因為最後希望得到的是[ {dic1},{dic2},{'建檔 ID':'811223', '分類':'教育訓練' ,...}, {dic4}....]的格式,所以還有一些問題:
1、'回報資料錯誤 ' 不是我們要的,
2、'電郵'、'網址'等有中斷,實際資料跑到list的下一個元素去了。(其實還有宗派、母會,每個教會的資料有些許不同)
先準備幾個資料:一個空的字典(dictionary)、2個空的串列(list),這個要在function外面。
myDict = {}
myList = []
tmpList = []
  1. def get_detail(url, s):
  2.     print(url)
  3.     res = s.get(url)
  4.     res.encoding = 'utf-8'
  5.     soup = BeautifulSoup(res.text, 'lxml')
  6.     detail = soup.find_all('td', 'church_detail')
  7.     for ddd in detail[0].stripped_strings:
  8.         if '回報資料錯誤 >' in ddd:
  9.         #如果字串是 '回報資料錯誤 >',不動作,直接進入下一次迴圈
  10.             continue         
  11.         else:
  12.             tmpList.append(ddd)  #其他的都放進tmpList裡

  13.     for i, s in enumerate(tmpList):
  14.         if s == "":
  15.          #如果是空字串,不動作,直接進入下一次迴圈
  16.             continue         
  17.         elif any(x in s for x in ['電郵', '網址', '宗派', '母會']):
  18.          #如果是'電郵', '網址', '宗派', '母會'其中之一,將其去除':'後做為key值,tmpList的下一個元素做為value,新增至myDict
  19.             myDict[s.replace(':', '')] = tmpList[i+1]   
  20.         else:                                                                        
  21.             try:
  22.                 myDict[s.split(':')[0]] = s.split(':')[1]
  23.           #其他的以':'分割,前部做為key值,後部做為value,新增至myDict  
  24.             except:
  25.           #如果有例外,跳過不處理
  26.                 pass
  27.           #將myDict整個放到myList裡                                               
  28.     myList.append(myDict)
複製代碼
這樣get_detail應該就差不多完成了,下午有空再來測試一下。

TOP

加了註解變得有點亂,附一個純code的。
  1. def get_detail(url, s):
  2.     print(url)
  3.     res = s.get(url)
  4.     res.encoding = 'utf-8'
  5.     soup = BeautifulSoup(res.text, 'lxml')
  6.     detail = soup.find_all('td', 'church_detail')
  7.     for ddd in detail[0].stripped_strings:
  8.         if '回報資料錯誤 >' in ddd:
  9.             continue
  10.         else:
  11.             tmpList.append(ddd)

  12.     for i, s in enumerate(tmpList):
  13.         if s == "":
  14.             continue
  15.         elif any(x in s for x in ['電郵', '網址', '宗派', '母會']):
  16.             myDict[s.replace(':', '')] = tmpList[i+1]
  17.         else:
  18.             try:
  19.                 myDict[s.split(':')[0]] = s.split(':')[1]
  20.             except:
  21.                 pass
  22.     myList.append(myDict)
複製代碼

TOP

回復 69# zyzzyva
有錯誤訊息,如下:
新增派工.png
2016-9-11 16:45

TOP

        靜思自在 : 一個人的快樂.不是因為他擁有得多,而是因為他計較得少。
返回列表 上一主題