如何通過爬蟲爬取公眾號的活躍度
- 2019 年 10 月 4 日
- 筆記
背景介紹
這篇文章主要來介紹下如何通過爬蟲技術來爬取測試相關公眾號的資訊,接著通過對爬取的資訊進行過濾處理給出測試公眾號活躍度的一個列表。這裡活躍度會以月發文的數量來進行衡量。
這篇文章的程式碼是在Python 3.x版本調試通過的。
爬取詳解
現在來具體介紹下爬蟲的步驟。因為搜狗搜索是可以進行微信公眾號資訊搜索的,因此我們主要是通過對搜索的搜索結果進行爬取,得到我們需要的資訊,可通過如下的鏈接進行微信公眾號資訊搜索:
https://weixin.sogou.com/
輸入需要搜索的公眾號,然後點擊右側的搜公眾號按鈕即可,如下圖所示:

爬蟲的一般步驟是獲取需要訪問的URL,通過分析試驗去構造請求的相關參數資訊,接著發送請求,最後獲取響應的資訊進行處理。
爬取的URL我們可以藉助瀏覽器的工具去獲取,比如使用Chrome,可以滑鼠右鍵選擇Inspect進行查看即可。首先我們打開上面給鏈接,打開微信公眾號搜索的首頁,然後滑鼠右鍵選擇Inspect,接著點擊Network tab, 點完後在搜索輸入框隨便輸入一個搜索關鍵字,如軟體測試,最後點擊下搜公眾號按鈕,瀏覽器會自動化將這個動作所發生的請求都列出來,我們可以通過查看這些請求去獲取我們需要爬取的URL和相關頭部資訊,如下所示:

通過觀察分析上面所發生的請求以及進行一定的試驗,可以知道獲取公眾號資訊的關鍵請求是類似如下的URL:
https://weixin.sogou.com/weixin?type=1&query=%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95&ie=utf8&s_from=input&_sug_=n&_sug_type_=
其中的query欄位的值根據經驗可以容易知道是通過對搜索關鍵字"軟體測試"進行urlencode過的的結果,因此到時候發請求的時候我們要介紹Python的庫對搜索關鍵字先進行urlencode操作,其他幾個欄位值和上面的URL保持一致即可。
通過實驗得知模擬發送上面的請求還需要添加如下的頭部資訊才能發送成功:
- host頭部
- User-Agent頭部
我們在來看下搜索結果的關於月發文數量的截圖:

通過實驗得知,通過一般的xpath並不能獲取到月發文數量這個控制項元素,因此需要再分析是否有其他途徑可以獲取到,經過分析發現,如下的URL返回的結果就包含的月發文的數量:

這個請求的URL拷貝出來,如下所示:
https://weixin.sogou.com/websearch/weixin/pc/anti_account.jsp?t=1567955232611&signature=afj0JGyeIpkQtGdWwBwy696pWaIImPGhhMt*eOEuVLeOXfRxcJE2DPUU51rZgzjIEvdlybryyq6Cujwsqru*MZPJghMn4B1Y1PKoBCjpnaAw-NDQjdMyEou5kvpozFDk7em6foePHdsJwW0NaBAJ43PB4Zv3ptqBFvwkXyWkmf*a2oyelgyNE6l7GsC8vcTD-5*4DXWvG-LaqAsAheIBIpuNDKGNzvTG5KKCe-hAFNT4R1I8e6MwEuMQGY8R32p8N8OzhAifZ7Fpfi92RwVlhZ4beoX0SUXAzqAPYaqBNxaY5hoiem*c-zkTlSr94XYBkczD-jg5eH75wvIHKpNejt*dgKW*G3g5yp4U2UYbadw1y1K*IGNLl15gsGydHjZtWpST1wQxY6XwVl8pe9DBaDwS30tTSsF3bxWq1WHPtRI=
可以發現這個URL很長,但仔細分析觀察可以知道這個URL的前置是不變的也就是https://weixin.sogou.com,後面的部分其實第一個搜索的URL的響應結果里已經有包含的,如下所示:

因此我們只要對第一個請求URL的響應結果編寫對應的正則提取出後面的URL然後和規定的前綴host進行拼接就可以構造出獲取發文數量的URL了。發文URL的返回里仔細分析可以知道可以通過data-id關聯到微信公眾號名稱,data-id就是如下截圖圈出來的部分

我們就是通過上面紅色圈出來的data-id去第一個搜索URL返回的結果里找到對應這個data-id的微信公眾號名稱,這樣我們就可以完整獲取到公眾號和其對應的發文數量了。
我在爬蟲程式的開始定義了個列表用來存放需要搜索的關鍵字,程式會遍歷這個關鍵字列表,每次獲取出該關鍵字搜索出來的公眾號及其對應的月發文數量,在外部還定義了個字典用來存放公眾號和對應月發文數量,最後遍歷結束後會對這個字典按值進行降序的排列,這樣就能得出搜索公眾號的活躍度排名了。
完整程式碼
import requests import urllib.parse import re from lxml import etree #定義字典,要來存放公眾號和對應的月發文數量 all_accounts = {} #定義需要搜索的公眾號的關鍵字,可以修改這個列表進行你需要的公眾號搜索 names = ['軟體測試','性能測試','測試開發','自動化測試','介面測試','Appium','webdriver','selenium','51testing軟體測試網','testerhome'] #遍歷關鍵字列表,將每次檢索出來的數據添加到上面的字典中,遍歷結束就可以獲取所有的搜索數據 for name in names: #對關鍵字進行urlencode query_str = urllib.parse.quote(name) url = 'https://weixin.sogou.com/weixin?type=1&query=' + query_str+'&ie=utf8&s_from=input&_sug_=y&_sug_type_=' headers = {} #設置必須的頭部資訊 headers['host'] = "weixin.sogou.com" headers['User-Agent'] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15" response = requests.get(url, headers=headers) #設置正則,用來提取獲取月發文數量的URL後面的path post_count_regex = re.compile( '<script>var account_anti_url = "(.*?)";</script>') post_count_url = post_count_regex.findall(response.text)[0] data = requests.get('http://weixin.sogou.com{}'.format(post_count_url)) # 獲取月發文數量,需要通過data-id關聯獲取 post_counts = data.json().get('msg') page = etree.HTML(response.text) lis = page.xpath('//ul[@class="news-list2"]/li') infors = {} for li in lis: data_id = li.get('d') if data_id not in post_counts: continue w_name = '' elements = li.xpath("div/div[2]/p[1]/a/descendant::text()") for ele in elements: w_name += ele count = post_counts['%s' % (data_id)].split(',')[0] infors.update({'%s' % (w_name): int(count)}) all_accounts.update(infors) #將字典按值降序排序 sorted_accounts = [(k, all_accounts[k]) for k in sorted(all_accounts, key=all_accounts.get, reverse=True)] for k, v in sorted_accounts: print(f'{k} : {v}')
執行結果如下所示:
51Testing軟體測試網 : 58 新夢想軟體測試 : 34 軟體測試培訓 : 34 TesterHome : 24 自動化軟體測試 : 21 北京尚腦軟體測試 : 20 軟體測試學園 : 10 自動化測試學堂 : 7 軟體測試部落 : 6 性能測試與調優 : 5 Python自動化測試 : 5 glx介面測試 : 2 軟體測試相關 : 1
遺留問題
因為搜狗搜索有防爬蟲的策略,太頻繁的訪問會返回待驗證碼的頁面回來造成程式執行失敗,可以添加判斷,如果有驗證碼返回通過截圖該驗證碼區域,通過OCR獲取後再輸入來完成流程,這個步驟還未實現。有興趣的可以自行擴展