.net core之ACG小站爬虫(一)
来源:互联网 发布:天通金行情分析软件 编辑:程序博客网 时间:2024/05/08 07:38
想到好久没写过.net的代码了,因此就尝试来写一写.net
的代码。此外,也想要熟悉一下Phantomjs。
环境配置
.net core下载。可选的可以下载宇宙大IDE
Visual Studio
,当然更加推荐使用Visual Studio Code进行代码的书写。Phantomjs。这个不用说了,今天的主角。采用无头浏览器爬取ACG小站的很大原因是它的页面很难分析,此外也有熟悉一下
Phantomjs
的意思。HttpCode.Core,是一个
.net core
的HTTP请求库,可以使用Nuget安装。库本质上是基于HttpWebRequest
实现的,但是为了舍去我们自己封装的麻烦,就采用此库来减少代码量。AngleSharp,一个帮助解析HTML的
.net
库,可以直接使用LINQ来查询,很方便。
页面分析
详情页
就以其中随便的一个动漫链接下载为例子,发现了坑爹的玩意,下载链接的href
属性是javascript:;
。介于浅薄的javascript
知识,百度了才知道这个是伪协议,实际运行了一段js
代码回调,从而打开了新的页面。但是这个网站是用React
写的,更可怕的在下面。
JavaScript
原本采用直接分析,并借助Debug调试来分析它点击后的回调函数,但是这个JavaScript
文件竟然有2万行代码,Chrome打开调试定点,根本就没法format,不然直接卡死,于是放弃了这个念头,转而采用无头浏览器进行爬取。
实现
一般采用Phantomjs
的手段都为Selenium+Phantomjs
,但是性能不是很好,而且暂时也没怎么找.net
的Selenium
接口,所以就选用了最近看到的直接让Phantomjs
作为服务端,然后去请求它,让它把要爬取的结果反馈给.net
。注意,这里的结果可以是网页页面,也可以是Phantomjs
进行HTML解析完的真实数据。
.Net Core代码
public async Task<string> GetDownloadPageAsync(string url) { string result = string.Empty; //请求phantomjs 获取下载页面 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; //输出错误信息 } return result; }
这里展示的是第一部分的代码,即请求详情页的代码,还未涉及到点了下载按钮之后页面的分析,实际上差不多。
JavaScript代码
"use strict";var port = 8088;var server = require('webserver').create();//服务端监听server.listen(8088, function (request, response) { //传入的参数有待更改,目前为 //{"Key":"https://acg12.com/200340/", "Value":"Tappable-inactive animated fadeIn"}的json字符窜 //第一个参数为详情页,第二个为下载按钮的Dom var data = JSON.parse(request.postRaw); var url = data.Key.toString(); var dom = data.Value.toString(); var code = 0; var page = require('webpage').create(); //初始化headers page.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' }; //根据Phantomjs的官网,这个回调在打开新标签页会触发 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端的响应内容。 }; }; //让Phantomjs帮助我们去请求页面 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 (){ //执行JavaScript代码,类似于在浏览器Console中执行JavaScript page.evaluate(function(dom) { console.log(dom); var btnList = document.getElementsByClassName(dom); if(btnList.length > 0){ var btn = document.getElementsByClassName(dom)[1]; // 获取下载按钮 btn.click(); //点击下载按钮,打开新标签页,触发page.onPageCreated回调函数。 } }, dom); }, 7000); } }); //根据Phantomjs的官网,这个回调主要应对执行evaluate函数内部的console.log输出,因为两个环境是隔离的。 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); };
这里的注释比较详细,就不细说了。
启动上述Phantomjs服务端的脚本
phantomjs --ssl-protocol=any --debug=true .\server_get_detail_page.js
第一个参数是为了保持ssl
的链接,第二个参数开启debug
,第三个参数为上面的JavaScript
代码。
还有之后的页面类似于以上的代码,但是有一些细节需要注意,为了防止文章过长(明明是再水一篇(๑ ̄ _  ̄๑))大家下期再见。等等,完整的源代码就先全放在Github上了
原文地址:http://www.jianshu.com/p/9b738a25b585
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
- .net core之ACG小站爬虫(一)
- .net core之ACG小站爬虫(二)
- ASP.NET Core 之 Identity 入门(一)
- ASP.NET Core 之 Identity 入门(一)
- [acg]
- NET Core-学习笔记(一)
- NET Core-学习笔记(一)
- 爬虫之旅(一)
- asp.net core MVC 过滤器之ExceptionFilter过滤器(一)
- asp.net core MVC 过滤器之ExceptionFilter过滤器(一)
- 爬虫爬虫爬虫(一)
- .Net Core 之 HelloWorld
- .NET应用迁移到.NET Core(一)
- Core Animation之框架简介(一)
- iOS 之Core Data操作(一)
- Core Animation(一)之常用属性
- core animation初识之CALayer(一)
- java爬虫 之 搜狐新闻爬虫(一)
- 654654366376576575477654
- 是时候开始用C#快速开发移动应用了
- 大湾区第二次.NET技术交流会圆满成功
- Java JVM:内存溢出(栈溢出,堆溢出,持久代溢出以及 nable to create native thread)
- asp.net core mvc View Component 应用
- .net core之ACG小站爬虫(一)
- .net core之ACG小站爬虫(二)
- Azure School与开源
- ASPNET Core 2.x中的Kestrel服务器
- 体验 ASP.NET Core 中的多语言支持(Localization)
- Fibonacci数列求余
- asp.net core 2.0 web api基于JWT自定义策略授权
- ASP.NET Core Web服务器 Kestrel和Http.sys 特性详解
- 王者荣耀是怎样炼成的(一)《王者荣耀》用什么开发,游戏入门,unity3D介绍