1. 程式人生 > >使用網頁爬蟲(高階搜尋功能)蒐集含關鍵詞新浪微博資料

使用網頁爬蟲(高階搜尋功能)蒐集含關鍵詞新浪微博資料

作為國內社交媒體的領航者,很遺憾,新浪微博沒有提供以“關鍵字+時間+區域”方式獲取的官方API。當我們看到國外科研成果都是基於某關鍵字獲得的社交媒體資料,心中不免涼了一大截,或者轉戰推特。再次建議微博能更開放些!


1、切入點

慶幸的是,新浪提供了高階搜尋功能。找不到?這個功能需要使用者登入才能使用……沒關係,下面將詳細講述如何在無須登入的情況下,獲取“關鍵字+時間+區域”的新浪微博。

首先我們還是要登入一下,看看到底是個什麼樣的功能。


然後我們看看位址列:

  1. http://s.weibo.com/wb/%25E4%25B8%25AD%25E5%259B%25BD%25E5%25A5%25BD%25E5%25A3%25B0%25E9%259F%25B3&
    xsort=time&region=custom:11:1000&timescope=custom:2014-07-09-2:2014-07-19-4&Refer=g

這麼長?其實蠻清晰、簡單的。解析如下:

固定地址部分:http://s.weibo.com/wb/

關鍵字(2次URLEncode編碼):%25E4%25B8%25AD%25E5%259B%25BD%25E5%25A5%25BD%25E5%25A3%25B0%25E9%259F%25B3

返回微博的排序方式(此處為“實時”):xsort=time

搜尋地區:region=custom:11:1000

搜尋時間範圍:timescope=custom:2013-07-02-2:2013-07-09-2

可忽略項:Refer=g

是否顯示類似微博(未出現):nodup=1    注:加上這個選項可多收集微博,建議加上。預設為省略引數,即省略部分相似微博。

某次請求的頁數(未出現):page=1

既然是這麼回事,我們接下來就可以使用網頁爬蟲的方式獲取“關鍵字+時間+區域”的微博了……

2、採集思路

大體思路如下:構造URL,爬取網頁,然後解析網頁中的微博資訊,如下圖所示。微博官方提供了根據微博ID進行查詢的微博資訊的API,故本文只負責講述收集微博ID。

另外,高階搜尋最多返回50頁微博,那麼時間間隔設定最小為宜。所以時間範圍(timescope)可設定為1小時,如2013-07-01-2:2013-07-01-2。

目前沒有模擬登陸,所以需要設定兩個鄰近URL請求之間的隨機休眠時間,過於頻繁會被認為是機器人,你懂的。



3、具體實現

作為爬蟲小工具,用python非常適合。作為python初學者,不要怪我寫得像java。首先實現一個爬取每個小時的類。

  1. class CollectData():  
  2.     """每小時資料收集類 
  3.         利用微博高階搜尋功能,按關鍵字蒐集一定時間範圍內的微博。 
  4.         大體思路:構造URL,爬取網頁,然後解析網頁中的微博ID。後續利用微博API進行資料入庫。本程式只負責收集微博的ID。 
  5.         登陸新浪微博,進入高階搜尋,輸入關鍵字”空氣汙染“,選擇”實時“,時間為”2013-07-02-2:2013-07-09-2“,地區為”北京“,之後傳送請求會發現位址列變為如下: 
  6.         http://s.weibo.com/wb/%25E7%25A9%25BA%25E6%25B0%2594%25E6%25B1%25A1%25E6%259F%2593&xsort=time&region=custom:11:1000×cope=custom:2013-07-02-2:2013-07-09-2&Refer=g 
  7.             固定地址部分:http://s.weibo.com/wb/ 
  8.             關鍵字二次UTF-8編碼:%25E7%25A9%25BA%25E6%25B0%2594%25E6%25B1%25A1%25E6%259F%2593 
  9.             排序為“實時”:xsort=time 
  10.             搜尋地區:region=custom:11:1000 
  11.             搜尋時間範圍:timescope=custom:2013-07-02-2:2013-07-09-2 
  12.             可忽略項:Refer=g 
  13.             顯示類似微博:nodup=1    注:這個選項可多收集微博,建議加上。預設不加此引數,省略了部分相似微博。 
  14.             某次請求的頁數:page=1 
  15.         另外,高階搜尋最多返回50頁微博,那麼時間間隔設定最小為宜。所以該類設定為蒐集一定時間段內最多50頁微博。 
  16.     """
  17.     def __init__(self, keyword, startTime, region, savedir, interval='50', flag=True, begin_url_per = "http://s.weibo.com/weibo/"):  
  18.         self.begin_url_per = begin_url_per  #設定固定地址部分,預設為"http://s.weibo.com/weibo/",或者"http://s.weibo.com/wb/"
  19.         self.setKeyword(keyword)    #設定關鍵字
  20.         self.setStartTimescope(startTime)   #設定搜尋的開始時間
  21.         self.setRegion(region)  #設定搜尋區域
  22.         self.setSave_dir(savedir)   #設定結果的儲存目錄
  23.         self.setInterval(interval)  #設定鄰近網頁請求之間的基礎時間間隔(注意:過於頻繁會被認為是機器人)
  24.         self.setFlag(flag)  #設定
  25.         self.logger = logging.getLogger('main.CollectData'#初始化日誌
  26.     ##設定關鍵字
  27.     ##關鍵字需解碼
  28.     def setKeyword(self, keyword):  
  29.         self.keyword = keyword.decode('GBK').encode("utf-8")  
  30.         print'twice encode:',self.getKeyWord()  
  31.     ##設定起始範圍,間隔為1小時
  32.     ##格式為:yyyy-mm-dd-HH
  33.     def setStartTimescope(self, startTime):  
  34.         ifnot (startTime == '-'):  
  35.             self.timescope = startTime + ":" + startTime  
  36.         else:  
  37.             self.timescope = '-'
  38.     ##設定搜尋地區
  39.     def setRegion(self, region):  
  40.         self.region = region  
  41.     ##設定結果的儲存目錄
  42.     def setSave_dir(self, save_dir):  
  43.         self.save_dir = save_dir  
  44.         ifnot os.path.exists(self.save_dir):  
  45.             os.mkdir(self.save_dir)  
  46.     ##設定鄰近網頁請求之間的基礎時間間隔
  47.     def setInterval(self, interval):  
  48.         self.interval = int(interval)  
  49.     ##設定是否被認為機器人的標誌。若為False,需要進入頁面,手動輸入驗證碼
  50.     def setFlag(self, flag):  
  51.         self.flag = flag  
  52.     ##構建URL
  53.     def getURL(self):  
  54.         returnself.begin_url_per+self.getKeyWord()+"&region=custom:"+self.region+"&xsort=time×cope=custom:"+self.timescope+"&nodup=1&page="
  55.     ##關鍵字需要進行兩次urlencode
  56.     def getKeyWord(self):  
  57.         once = urllib.urlencode({"kw":self.keyword})[3:]  
  58.         return urllib.urlencode({"kw":once})[3:]  
  59.     ##爬取一次請求中的所有網頁,最多返回50頁
  60.     def download(self, url, maxTryNum=4):  
  61.         content = open(self.save_dir + os.sep + "weibo_ids.txt""ab")  #向結果檔案中寫微博ID
  62.         hasMore = True#某次請求可能少於50頁,設定標記,判斷是否還有下一頁
  63.         isCaught = False#某次請求被認為是機器人,設定標記,判斷是否被抓住。抓住後,需要複製log中的檔案,進入頁面,輸入驗證碼
  64.         mid_filter = set([])    #過濾重複的微博ID
  65.         i = 1#記錄本次請求所返回的頁數
  66.         while hasMore and i < 51and (not isCaught):    #最多返回50頁,對每頁進行解析,並寫入結果檔案
  67.             source_url = url + str(i)   #構建某頁的URL
  68.             data = ''#儲存該頁的網頁資料
  69.             goon = True#網路中斷標記
  70.             ##網路不好的情況,試著嘗試請求三次
  71.             for tryNum in range(maxTryNum):  
  72.                 try:  
  73.                     html = urllib2.urlopen(source_url, timeout=12)  
  74.                     data = html.read()  
  75.                     break
  76.                 except:  
  77.                     if tryNum < (maxTryNum-1):  
  78.                         time.sleep(10)  
  79.                     else:  
  80.                         print'Internet Connect Error!'
  81.                         self.logger.error('Internet Connect Error!')  
  82.                         self.logger.info('filePath: ' + savedir)  
  83.                         self.logger.info('url: ' + source_url)  <