Author: Hoyho Luohtml
Email: luohaihao@gmail.comnode
Source Url:https://here2say.tw/11/git
轉載請保留此出處github
本文介紹基於搜狗的微信公衆號定向爬蟲,使用C#實現,故取名WeGouSharp。本文中的項目託管在Github上,你能夠戳WeGouSharp獲取源碼,歡迎點星。關於微信公共號爬蟲的項目網上已經很多,然而基本大多數的都是使用Python實現 鑑於鄙人是名.NET開發人員,因而又爲廣大微軟系同胞建立了這個輪子,使用C#實現的微信爬蟲 藍本爲Chyroc/WechatSogou, 在此還請各位大佬指教。chrome
目錄 1.項目結構 2.數據結構 3.xpath介紹 4.使用HtmlAgilityPack解析網頁內容 5.驗證碼處理以及文件緩存
以下圖json
API類:api
全部直接的操做封裝好在API類中,直接使用裏面的方法緩存
本項目根據微信公帳號以及搜狗搜索定義了多個結構,能夠查看模型類,主要包括如下:bash
公衆號結構:微信
public struct OfficialAccount { public string AccountPageurl; public string WeChatId; public string Name; public string Introduction; public bool IsAuth; public string QrCode; public string ProfilePicture;//public string RecentArticleUrl; }
字段含義
字段 | 含義 |
---|---|
AccountPageurl | 微信公衆號頁 |
WeChatId | 公號ID(惟一) |
Name | 名稱 |
Introduction | 介紹 |
IsAuth | 是否官方認證 |
QrCode | 二維碼連接 |
ProfilePicture | 頭像連接 |
字段含義
字段 | 含義 |
---|---|
Meaasgeid | 消息號 |
SendDate | 發出時間(unix時間戳) |
Type | 消息類型:49:圖文, 1:文字, 3:圖片, 34:音頻, 62:視頻 |
Content | 文本內容(針對類型1即文字) |
ImageUrl | 圖片(針對類型3,即圖片) |
PlayLength | 播放長度(針對類型34,即音頻,下同) |
FileId | 音頻文件id |
AudioSrc | 音頻源 |
ContentUrl | 文章來源(針對類型49,即圖文,下同) |
Main | 不明確 |
Title | 文章標題 |
Digest | 不明確 |
SourceUrl | 多是閱讀原文 |
Cover | 封面圖 |
Author | 做者 |
CopyrightStat | 多是否原創? |
CdnVideoId | 視頻id(針對類型62,即視頻,下同) |
Thumb | 視頻縮略圖 |
VideoSrc | 視頻連接 |
public struct HotWord { public int Rank;//排行 public string Word; public string JumpLink; //相關連接 public int HotDegree; //熱度 }
簡而言之,Xpath是XML元素的位置,下面是W3C教程時間,老鳥直接跳過
咱們將在下面的例子中使用這個 XML 文檔。
<?xml version="1.0" encoding="ISO-8859-1"?> <bookstore> <book> <title lang="eng">Harry Potter</title> <price>29.99</price> </book> <book> <title lang="eng">Learning XML</title> <price>39.95</price> </book> </bookstore>
XPath 使用路徑表達式在 XML 文檔中選取節點。節點是經過沿着路徑或者 step 來選取的。
表達式 | 描述 |
---|---|
nodename | 選取此節點的全部子節點。 |
/ | 從根節點選取。 |
// | 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。 |
. | 選取當前節點。 |
.. | 選取當前節點的父節點。 |
@ | 選取屬性。 |
在下面的表格中,咱們已列出了一些路徑表達式以及表達式的結果:
路徑表達式 | 結果 |
---|---|
bookstore | 選取 bookstore 元素的全部子節點。 |
/bookstore | 選取根元素 bookstore。 註釋:假如路徑起始於正斜槓( / ),則此路徑始終表明到某元素的絕對路徑! |
bookstore/book | 選取屬於 bookstore 的子元素的全部 book 元素。 |
//book | 選取全部 book 子元素,而無論它們在文檔中的位置。 |
bookstore//book | 選擇屬於 bookstore 元素的後代的全部 book 元素,而無論它們位於 bookstore 之下的什麼位置。 |
//@lang | 選取名爲 lang 的全部屬性。 |
謂語用來查找某個特定的節點或者包含某個指定的值的節點。
謂語被嵌在方括號中。
在下面的表格中,咱們列出了帶有謂語的一些路徑表達式,以及表達式的結果:
路徑表達式 | 結果 |
---|---|
/bookstore/book[1] | 選取屬於 bookstore 子元素的第一個 book 元素。 |
/bookstore/book[last()] | 選取屬於 bookstore 子元素的最後一個 book 元素。 |
/bookstore/book[last()-1] | 選取屬於 bookstore 子元素的倒數第二個 book 元素。 |
/bookstore/book[position()<3] | 選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 選取全部擁有名爲 lang 的屬性的 title 元素。 |
//title[@lang='eng'] | 選取全部 title 元素,且這些元素擁有值爲 eng 的 lang 屬性。 |
/bookstore/book[price>35.00] | 選取 bookstore 元素的全部 book 元素,且其中的 price 元素的值須大於 35.00。 |
/bookstore/book[price>35.00]/title | 選取 bookstore 元素中的 book 元素的全部 title 元素,且其中的 price 元素的值須大於 35.00。 |
XPath 通配符可用來選取未知的 XML 元素。
通配符 | 描述 |
---|---|
* | 匹配任何元素節點。 |
@* | 匹配任何屬性節點。 |
node() | 匹配任何類型的節點。 |
在下面的表格中,咱們列出了一些路徑表達式,以及這些表達式的結果:
路徑表達式 | 結果 |
---|---|
/bookstore/* | 選取 bookstore 元素的全部子元素。 |
//* | 選取文檔中的全部元素。 |
//title[@*] | 選取全部帶有屬性的 title 元素。 |
如圖,假設我要抓取首頁一個banner圖,能夠在chrome按下F12參考該元素的Xpath,
即該圖片對應的Xpth爲: //*[@id="loginWrap"]/div[4]/div[1]/div[1]/div/a[4]/img
HttpTool類裏封裝了一個較多參數的HTTP GET操做,用於獲取搜狗的頁面:
由於搜狗自己是作搜索引擎的緣故,因此反爬蟲是很是嚴厲的,所以HTTP GET的方法要注意攜帶不少參數,且不一樣頁面要求不同.通常地,要帶上默認的
referer和host 而後請求頭的UserAgent 要僞造,經常使用的useragent有
public static List<string> _agent = new List<string> { "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)", "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20", "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52", };
自定義的GET 方法
前面關於Xpath廢話太多,直接上一個案例,解析公衆號頁面:
/// <summary> /// 頁面出現驗證碼,輸入才能繼續,此驗證依賴cookie, 獲取驗證碼的requset有個cookie,每次不一樣,須要在post驗證碼的時候帶上 /// </summary> /// <returns></returns> public bool VerifyCodeForContinute(string url ,bool isUseOCR) { bool isSuccess = false; logger.Debug("vcode appear, use VerifyCodeForContinute()"); DateTime Epoch = new DateTime(1970, 1, 1,0,0,0,0); var timeStamp17 = (DateTime.UtcNow - Epoch).TotalMilliseconds.ToString("R"); //get timestamp with 17 bit string codeurl = "https://mp.weixin.qq.com/mp/verifycode?cert=" + timeStamp17; WebHeaderCollection headers = new WebHeaderCollection(); var content = this.Get(headers, codeurl,"UTF-8",true); ShowImageHandle showImageHandle = new ShowImageHandle(DisplayImageFromBase64); showImageHandle.BeginInvoke(content, null, null); Console.WriteLine("請輸入驗證碼:"); string verifyCode = Console.ReadLine(); string postURL = "https://mp.weixin.qq.com/mp/verifycode"; timeStamp17 = (DateTime.UtcNow - Epoch).TotalMilliseconds.ToString("R"); //get timestamp with 17 bit string postData = string.Format("cert={0}&input={1}",timeStamp17,verifyCode );// "{" + string.Format(@"'cert':'{0}','input':'{1}'", timeStamp17, verifyCode) + "}"; headers.Add("Host", "mp.weixin.qq.com"); headers.Add("Referer", url); string remsg = this.Post(postURL, headers, postData,true); try { JObject jo = JObject.Parse(remsg);//把json字符串轉化爲json對象 int statusCode = (int)jo.GetValue("ret"); if (statusCode == 0) { isSuccess = true; } else { logger.Error("cannot unblock because " + jo.GetValue("msg")); var vcodeException = new WechatSogouVcodeException(); vcodeException.MoreInfo = "cannot jiefeng because " + jo.GetValue("msg"); throw vcodeException; } }catch(Exception e) { logger.Error(e); } return isSuccess; }
var timeStamp17 = (DateTime.UtcNow - Epoch).TotalMilliseconds.ToString("R"); //get timestamp with 17 bit