【问题标题】:Firing onclick event which triggers a POST request in jsdom触发在 jsdom 中触发 POST 请求的 onclick 事件
【发布时间】:2018-07-19 16:57:35
【问题描述】:

我正在尝试抓取 poorly designed governmental website,它使用从 JavaScript 触发的 POST 请求进行导航(我正在尝试导航日历)。

我正在尝试以优雅的方式做到这一点,在节点中使用 jsdom 和 jQuery(可能还有 jsdom-simulant),但我不确定我应该如何在模拟器中触发事件,因为事件本身应该回到 jsdom 并触发一个新的 HTTP POST 请求。

我不希望你们为我编写代码,我只需要一些关于结构、理念或执行类似操作的现有代码库的指针。

【问题讨论】:

    标签: node.js web-scraping jsdom


    【解决方案1】:

    关于抓取部分,这是一个 POST 请求发送表单 url 编码数据。有效载荷中有 2 个字段似乎是必需的:

    • __EVENTTARGET=ctl00$B_Center$VoturiPlen1$calVOT
    • __EVENTARGUMENT=XXXX(带有 XXXX 一些值)

    __EVENTARGUMENT 值每天都在递增。例如,2018 年 4 月 4 日为 6668,2018 年 5 月 4 日为 6669。查看最早的日期,即 1998 年 1 月 1 日,索引为 -730,因此可以使用差值计算该索引目标日期和 1998 年 1 月 1 日之间的天数减去 730

    使用 & dateutils

    target_date="2018-04-04"
    index=$(($(dateutils.ddiff 1998-01-01 "$target_date") - 730))
    
    curl 'https://www.senat.ro/Voturiplen.aspx' \
         -H 'User-Agent: Mozilla' \
         -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
         --data "__EVENTTARGET=ctl00%24B_Center%24VoturiPlen1%24calVOT&__EVENTARGUMENT=$index"
    

    并使用 html 解析器:

    curl 'https://www.senat.ro/Voturiplen.aspx' \
         -H 'User-Agent: Mozilla' \
         -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
         --data "__EVENTTARGET=ctl00%24B_Center%24VoturiPlen1%24calVOT&__EVENTARGUMENT=$index" | \
         pup 'table#ctl00_B_Center_VoturiPlen1_GridVoturi'
    

    使用,你可以使用

    const request = require('request');
    const moment = require('moment');
    const jsdom = require("jsdom");
    const {JSDOM} = jsdom;
    
    var a = moment('21/12/2017', 'DD/MM/YYYY');
    var b = moment('01/01/1998', 'DD/MM/YYYY');
    var index = a.diff(b, 'days') - 730;
    
    request.post({
        url: 'https://www.senat.ro/Voturiplen.aspx',
        form: {
            "__EVENTTARGET": "ctl00$B_Center$VoturiPlen1$calVOT",
            "__EVENTARGUMENT": index
        },
        headers: {
            'User-Agent': 'Mozilla'
        }
    },
    function(err, httpResponse, body) {
        const dom = new JSDOM(body);
        var table = dom.window.document.querySelector("#ctl00_B_Center_VoturiPlen1_GridVoturi");
        console.log(table.textContent);
    });
    

    检查this post 的日期差异

    【讨论】:

    • 哇,我印象深刻,你真的潜入了这个东西!谢谢,这是一个了不起的答案!我有点希望有一种相当简单的方法可以把所有的砖块放在一起,基本上得到一个无头浏览器,因为这样我就可以抓取任何网页,不管它的拜占庭导航逻辑如何;如果我找不到其他解决方案,我将不得不采用类似于您描述的解决方案。再次感谢您抽出宝贵时间对此进行深入研究!
    • 我不确定,但我认为在这里使用 dom 操作(模拟点击链接)会更复杂,因为您必须在点击日期之前点击年份和月份(除了如果您已经在正确的月份和年份)。所以你必须处理状态(例如点击年份链接,等待页面加载,点击月份链接,等待页面加载,点击日期链接,最后解析结果表),这将使算法复杂化。请注意,我可能是错的,只是我今天下午的一些想法
    • 我最终在 C# 中实现了您的解决方案,这些天我更舒服 - 我计划使用节点,因为它具有本机执行 javascript 的暂定能力,但因为它失败了......作为记录,无论如何,整个方法都必须是有状态的,因为 ASP.Net 中的实现完全是愚蠢的,它使用非常脆弱(且非 RESTful)的VIEWSTATE 变量来描述界面的整个状态,包括分页。 AngleSharp 救援。
    猜你喜欢
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 2022-01-23
    • 2017-07-30
    • 2010-10-21
    • 2020-01-31
    相关资源
    最近更新 更多