.net core之ACG小站爬虫(一)
想到好久沒寫過.net的代碼了,因此就嘗試來寫一寫.net的代碼。此外,也想要熟悉一下Phantomjs。
環(huán)境配置
.net core下載。可選的可以下載宇宙大IDEVisual Studio,當(dāng)然更加推薦使用Visual Studio Code進(jìn)行代碼的書寫。
Phantomjs。這個(gè)不用說了,今天的主角。采用無頭瀏覽器爬取ACG小站的很大原因是它的頁(yè)面很難分析,此外也有熟悉一下Phantomjs的意思。
HttpCode.Core,是一個(gè).net core的HTTP請(qǐng)求庫(kù),可以使用Nuget安裝。庫(kù)本質(zhì)上是基于HttpWebRequest實(shí)現(xiàn)的,但是為了舍去我們自己封裝的麻煩,就采用此庫(kù)來減少代碼量。
AngleSharp,一個(gè)幫助解析HTML的.net庫(kù),可以直接使用LINQ來查詢,很方便。
頁(yè)面分析
詳情頁(yè)
就以其中隨便的一個(gè)動(dòng)漫鏈接下載為例子,發(fā)現(xiàn)了坑爹的玩意,下載鏈接的href屬性是javascript:;。介于淺薄的javascript知識(shí),百度了才知道這個(gè)是偽協(xié)議,實(shí)際運(yùn)行了一段js代碼回調(diào),從而打開了新的頁(yè)面。但是這個(gè)網(wǎng)站是用React寫的,更可怕的在下面。
JavaScript
原本采用直接分析,并借助Debug調(diào)試來分析它點(diǎn)擊后的回調(diào)函數(shù),但是這個(gè)JavaScript文件竟然有2萬行代碼,Chrome打開調(diào)試定點(diǎn),根本就沒法format,不然直接卡死,于是放棄了這個(gè)念頭,轉(zhuǎn)而采用無頭瀏覽器進(jìn)行爬取。
實(shí)現(xiàn)
一般采用Phantomjs的手段都為Selenium+Phantomjs,但是性能不是很好,而且暫時(shí)也沒怎么找.net的Selenium接口,所以就選用了最近看到的直接讓Phantomjs作為服務(wù)端,然后去請(qǐng)求它,讓它把要爬取的結(jié)果反饋給.net。注意,這里的結(jié)果可以是網(wǎng)頁(yè)頁(yè)面,也可以是Phantomjs進(jìn)行HTML解析完的真實(shí)數(shù)據(jù)。
.Net Core代碼
? ? ? ?public async Task<string> GetDownloadPageAsync(string url){string result = string.Empty;//請(qǐng)求phantomjs 獲取下載頁(yè)面string dom = "Tappable-inactive animated fadeIn";KeyValuePair<string, string> url2dom = new KeyValuePair<string, string>(url, dom);var postData = JsonConvert.SerializeObject(url2dom);CookieContainer cc = new CookieContainer(); ?HttpHelpers helper = new HttpHelpers(); ?HttpItems items = new HttpItems();HttpResults hr = new HttpResults();items.Url = "http://localhost:8088/";items.Method = "POST";items.Container = cc;items.Postdata = postData;items.Timeout = 100000;hr = await helper.GetHtmlAsync(items);var downloadPageUrl = hr.Html;Console.WriteLine($"first => { downloadPageUrl }");if(downloadPageUrl.Contains("http")){# TODO}else{result = downloadPageUrl; //輸出錯(cuò)誤信息}return result;}這里展示的是第一部分的代碼,即請(qǐng)求詳情頁(yè)的代碼,還未涉及到點(diǎn)了下載按鈕之后頁(yè)面的分析,實(shí)際上差不多。
JavaScript代碼
"use strict"; var port = 8088; var server = require('webserver').create();//服務(wù)端監(jiān)聽 server.listen(8088, function (request, response) {//傳入的參數(shù)有待更改,目前為//{"Key":"https://acg12.com/200340/", "Value":"Tappable-inactive animated fadeIn"}的json字符竄//第一個(gè)參數(shù)為詳情頁(yè),第二個(gè)為下載按鈕的Domvar data = JSON.parse(request.postRaw);var url = data.Key.toString();var dom = data.Value.toString();var code = 0;var page = require('webpage').create();//初始化headerspage.onInitialized = function() {page.customHeaders = {};};page.settings.loadImages = false;page.customHeaders = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36","Referer": url};response.headers = {'Cache': 'no-cache','Content-Type': 'text/plain','Connection': 'Keep-Alive','Keep-Alive': 'timeout=20, max=100'};//根據(jù)Phantomjs的官網(wǎng),這個(gè)回調(diào)在打開新標(biāo)簽頁(yè)會(huì)觸發(fā)page.onPageCreated = function(newPage) {//console.log('A new child page was created! Its requested URL is not yet available, though.');newPage.onLoadFinished = function(status) {console.log('A child page is Loaded: ' + newPage.url);//newPage.render('newPage.png');response.write(newPage.url);response.statusCode = code;response.close(); //寫入返回給.net端的響應(yīng)內(nèi)容。};};//讓Phantomjs幫助我們?nèi)フ?qǐng)求頁(yè)面page.open(url, function (status) {console.log("----" + status);if (status !== 'success') {code = 400;response.write('4XX');response.statusCode = code;response.close();} else {code = 200;window.setTimeout(function (){//執(zhí)行JavaScript代碼,類似于在瀏覽器Console中執(zhí)行JavaScriptpage.evaluate(function(dom) {console.log(dom);var btnList = document.getElementsByClassName(dom);if(btnList.length > 0){var btn = document.getElementsByClassName(dom)[1]; // 獲取下載按鈕btn.click(); //點(diǎn)擊下載按鈕,打開新標(biāo)簽頁(yè),觸發(fā)page.onPageCreated回調(diào)函數(shù)。}}, dom); ? ? ? ?}, 7000);}});//根據(jù)Phantomjs的官網(wǎng),這個(gè)回調(diào)主要應(yīng)對(duì)執(zhí)行evaluate函數(shù)內(nèi)部的console.log輸出,因?yàn)閮蓚€(gè)環(huán)境是隔離的。page.onConsoleMessage = function(msg, lineNum, sourceId) {console.log("$$$$$" + msg);};page.onError = function(msg, trace) {var msgStack = ['PHANTOM ERROR: ' + msg];if (trace && trace.length) {msgStack.push('TRACE:');trace.forEach(function(t) {msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function +')' : ''));});}console.log(msgStack.join('\n'));phantom.exit(1);}; }); phantom.onError = function(msg, trace) {var msgStack = ['PHANTOM ERROR: ' + msg];if (trace && trace.length) {msgStack.push('TRACE:');trace.forEach(function(t) {msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function +')' : ''));});}console.log(msgStack.join('\n'));phantom.exit(1);};這里的注釋比較詳細(xì),就不細(xì)說了。
啟動(dòng)上述Phantomjs服務(wù)端的腳本
phantomjs ?--ssl-protocol=any --debug=true .\server_get_detail_page.js第一個(gè)參數(shù)是為了保持ssl的鏈接,第二個(gè)參數(shù)開啟debug,第三個(gè)參數(shù)為上面的JavaScript代碼。
還有之后的頁(yè)面類似于以上的代碼,但是有一些細(xì)節(jié)需要注意,為了防止文章過長(zhǎng)(明明是再水一篇(? ̄ _ ? ̄?))大家下期再見。等等,完整的源代碼就先全放在Github上了
原文地址:http://www.jianshu.com/p/9b738a25b585
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的.net core之ACG小站爬虫(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .net core之ACG小站爬虫(二)
- 下一篇: asp.net core mvc Vie