.net core之ACG小站爬虫(二)

紧跟着上一节说的文章,虽然已经放出了所写的全代码,但还是再解释一下另外一个页面的请求和分析过程吧。

PS:又可以愉快的水一章了,咕嘿嘿。


页面分析

上回说到下载按钮的href属性是javascript:;伪协议,导致了新打开的页面链接携带#符号,但是我们通过了phantomjs已经解决了第一次跳转的问题。

下载页面

事实证明,这里更加狠,连个伪协议都没有。不过没关系,我们还是沿用上回的那个方法,使用phantomjs来渲染页面并且将跳转的页面链接以响应返回给我们的客户端请求。

实现

采用上一节所说的让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 = this.PostUrl1;
            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"))
            {
                //获取百度云下载地址和分享密码
                //string code1 = "1";
                dom = "Tappable-inactive btn btn-success btn-block"; // 下载链接
                url2dom = new KeyValuePair<string, string>(downloadPageUrl, dom);
                postData = JsonConvert.SerializeObject(url2dom);
                items = new HttpItems
                {
                    Url = this.PostUrl2
                };
                items.Method = "POST";
                items.Container = cc;
                items.Postdata = postData;
                items.Timeout = 1000000;
                hr = await helper.GetHtmlAsync(items);
                result = hr.Html; //返回json数据
                Console.WriteLine($"second => { result }");
            }
            else
            {
                result = downloadPageUrl; //输出错误信息
            }
            return result;
        }

这里包含了第一次在详情页获取下载页的那个请求,以及下载页面获取百度云链接和分享密码的请求。

JavaScript代码

"use strict";
var port = 8089;
var server = require('webserver').create();
 
server.listen(8089, function (request, response) {
    //传入的参数有待更改,目前为
    //{"Key":"https://acg12.com/download/#60e21d8417ab60fbfJfcqnT1BC8Qd20PehAIKv3J4ZO%2FJCo0htE9hP5IFZU", 
    //"Value":"Tappable-inactive btn btn-success btn-block"}的json字符窜
    //第一个参数为经过第一次请求所返回的下载页面,第二个为下载按钮的Dom
    var data = JSON.parse(request.postRaw);
    var url = data.Key.toString();
    console.log(url);
    var dom = data.Value.toString();
    console.log(dom);
    var code = 200;
    var pwdArray = new Array();
    var result = new Array();
    var page = require('webpage').create();
    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=40, max=100'
    };
    //根据Phantomjs的官网,这个回调在打开新标签页会触发
    page.onPageCreated = function(newPage) {
        //console.log('A new child page was created! Its requested URL is not yet available, though.');
        page.onInitialized = function() {
          newPage.customHeaders = {};
        };
        newPage.settings.loadImages = false;
        newPage.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"
        };
        //newPage.viewportSize = { width: 1920, height: 1080 };
        //当百度云页面打开并渲染完成时触发
        newPage.onLoadFinished = function(status) {
            //console.log('A child page is Loaded: ' + newPage.url);
            //newPage.render('newPage.png', {format: 'png', quality: '100'});
            //console.log(pwdArray.length);
            if(pwdArray.length > 0){
                //console.log("enter");
                //从数组中pop出密码,当无密码时pop的数据为null字符窜
                var temp = {"url": newPage.url.toString(), "password": pwdArray.pop().toString()};
                console.log(JSON.stringify(temp));
                result.push(temp); // 将json数据push进返回结果
            }
        };
    };
    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 (){
                //var dom = dom;
                pwdArray = page.evaluate(function(dom) {
                    console.log(dom);
                    var pwdArray = new Array();
                    var btnList = document.getElementsByClassName(dom); // 百度云链接
                    for(var i = 0; i < btnList.length;i ++ ){
                        //猜测所有下载节点都有密码
                        var temp = document.getElementById("downloadPwd-" + i);
                        if(temp != undefined){
                            //console.log("****" + temp.value);
                            pwdArray.push(temp.value); // 有密码push进数组
                        }else{
                            //console.log("****null");
                            pwdArray.push("null"); // 无密码则push进null字符窜,这样做到和url的一一对应
                        }
                    }
                    for(var i = 0; i < btnList.length;i ++ ){
                        //console.log("click");
                        btnList[i].click(); // 点击下载,打开新标签页
                    }
                    return pwdArray;
                }, dom);
            }, 6000);
        }
    });
    //设置等待20秒后才发送客户端的响应结果,这样保证上述方法都能成功运行结束
    window.setTimeout(function(){
        var rs = JSON.stringify(result)
        console.log(rs);
        response.write(rs);
        response.statusCode = code;
        response.close();
    }, 20000);
    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);
 };

完整的源代码已经放在Github上了,里面有写好的bat文件,直接运行run.bat就行。当然前提,第一节的那些环境都配置完成了。大家下周见,下周可能可以尝试用用DotnetSpider,这是借鉴了WebMagic写的.net core地爬虫框架,有兴趣的可以先去尝试一下玩玩。
谢谢~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,275评论 25 707
  • 很抱歉上周有事所以没有更新,再加上这个phantomjs的爬虫写的着实蛋疼。不过好在成功运行,特拿出来作为本周的例...
    浅浅的笑意阅读 2,564评论 0 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,982评论 4 60
  • 我怕孤独 更怕不曾孤独 闭上眼 等待风吹 不愿思索 清醒或沉睡 敝月的乌云 仿佛无力下雪 此时我想 或许浓云只是 ...
    染墨I阅读 176评论 0 2