RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1601407
Accepted
rennug
rennug
Asked:2024-12-02 05:29:50 +0000 UTC2024-12-02 05:29:50 +0000 UTC 2024-12-02 05:29:50 +0000 UTC

C# GetStringAsync 返回“错误”的 html

  • 772

我想解析 Perekrestok 商店的网站。

https://www.perekrestok.ru/cat/c/104/rastitelnoe-maslo

我编写了代码,一切正常,我得到了 html,我使用正则表达式做了我需要的事情。一周过去了,代码停止工作。抛出异常 403。我添加了一个标头(假装是浏览器),然后它再次开始返回 html,但不是我需要的。之前收到一个1MB左右的大文本,就好像我在浏览器里右键,看页面代码一样。现在我得到了一个22kB的小东西,里面没有商品,它们的价格等等。不。通过浏览器,一切都有效并且仍然有效。如果该网站认为我在发送垃圾邮件,我会理解,但我每 2 天就会解析 15 个链接。我不知道在哪里附上“错误”html 的示例。在这里复制粘贴是不人道的

https://dropmefiles.com/N9fRZ(22kB 文本文件,内含 html)

您需要获得与点击链接、右键单击并单击“查看页面代码”或从中提取产品、价格等相同的 html。

var client = new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36");
string html = await client.GetStringAsync("https://www.perekrestok.ru/cat/c/104/rastitelnoe-maslo");```

c#
  • 1 1 个回答
  • 70 Views

1 个回答

  • Voted
  1. Best Answer
    EvgeniyZ
    2024-12-02T11:38:10Z2024-12-02T11:38:10Z

    只有这个网站的作者才会回答你“为什么它有效然后不起作用”的答案,因为我们不知道那里有什么以及改变了什么,但我们可以知道现在有什么。嗯,现在有以下内容:

    如果您仔细观察该网站的行为方式,您会注意到以下图片:

    要求

    看到 2 个标记为 HTML 的请求吗?这就是该网站“幕后”所做的事情。当您第一次访问它时,您会收到一个“存根”页面,其中数据处理指示器在视觉上旋转,并且“在引擎盖下”生成了 2 个安装在浏览器 Cookie 中的唯一密钥。实际上,你现在卡在第一个请求上,因为请求的各种事情HttpClient都是干活,它们不会为你执行 JS 脚本(就像浏览器那样),你必须自己承担这项工作。

    其实,该怎么办呢?

    选项 3。

    1. 解析所有密钥生成逻辑并在 C# 中重复相同的操作。
    2. 在 C# 中执行 JS 脚本(类似的库负责此操作Jint,但请记住,部分逻辑放置在单独的第三方库中(在请求屏幕上位于 #15 下))
    3. 使用功能齐全的浏览器,它可以为我们做所有事情(WebView2、Selenium等)。

    我个人会走第一种路线,因为我认为它占用资源更少并且更可靠,并且在这个例子中没有什么特别复杂的。

    我们手动生成必要的 Cookie

    分析网站

    首先,让我们以编程方式向站点发送请求:

    private static readonly HttpClient client = new();
    
    static async Task Main(string[] args)
    {
        var url = "https://www.perekrestok.ru/cat/c/104/rastitelnoe-maslo";
        var html = await client.GetStringAsync(url);
    }
    

    并且...我们收到 403 错误。为什么?问题是该网站还会检查UserAgent,如果没有设置,那么该网站会立即停止让我们进入。实际上,我们像您一样添加它 ( client.DefaultRequestHeaders.Add(...)),然后重试。现在该网站为我们提供了必要的数据,我们查看它并了解那里发生了什么:

    function get_cookie_spsn() {
      return "spsn=1733103360750_";
    }
    function get_cookie_spid() {
      return "spid=1733103360750_2ad559e121cac55bda82f87420944787_sn1qo9g9rhfn5l0n";
    }
    function get_cookie_spsc_encrypted_part() {
      let func = function () {/*-----BEGIN RSA PRIVATE KEY-----
    MIICXQIBAAKBgQDCUJbXKTolYbHG5pFEq/iL8kY603vI7M8D3hTfi7CE9mQ20fzs
    z0qKfhl0K3zpQuGPX9vdUbtnfpI/TuzWH6acmq4lL9yCP8Wbx+ONaOMdChvb39+c
    jRPW1W+k6GopuQCOtcnLx9OzJIQG29bnF0HVQL2JgdKiAAASeay7hDsO7QIDAQAB
    AoGBAISojDJcPQwkREBsTKS7WzX/sx6aHxovQa18QnfTYDGGHSin96qcYmFmcW4z
    +lUtidxeLzZLhEvFx4ZdFaeheBajczGA4MDIMJl2siuzudVEG3+sTfwPuKAsYHAz
    DL7HjYUnJuxPYBC5J6E8+aaiid8/0UdvgvCwmn8odm3H5YMpAkEA+2QI7yqm9Q1I
    8ghmwfXO+TO8MYHJ/4MFH507oSRIkLDMQ6uSNFrs/TwNAblMB5SRHwj9ddJ6f+jq
    MgM3ZTExMwJBAMXgp3Mc43fvtigUMalDmvRZ4jszxBQrmmAwA80nuigdhOBi17AI
    Rga78OZa4DZo55Fg1N45k3ioK1ddZ50o/18CQHmliZE6IXpZSGAeYqMe8F20hC+s
    r3OeEf+fVTh/10F03BMu1dvR1/YedejMopbUdHkBH61BAZgdvB4hYk/sQvMCQFXl
    lKrqsm+g9kDlqz0f5McHsaYjbY2X8/anQS8wfKXnUoQZRCndHZDUytkkP8o+ta8t
    CprBAZxR3CabnFvjrR8CQQDVXv4jmj5R6N8qw8DmoCS7tOpjWNBCgvAHcPLZCHDw
    Y+yj975UBfWAgeZ8uQEplmW+zCKRupAKA52lJHBO/Irx
    -----END RSA PRIVATE KEY-----
    */};
      let pem = func.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];
      return KJUR.crypto.Cipher.decrypt("3a5dc07e2df1c2a51c24cb28d378e6bc2c7bc77108e4a00c7780fc6258dca6d5e2f61c7a1230f1d98a85e5a45044872ce9d1c77e228e51a0116a2f4560d7182ae0cdc2588ef16417aea865a70eb5cb2335c72b34b371ffbb08019d2bfb641d382f3853413c530a0e5940a0bfae9ce911101fbd592529e4d4d1e9c2a571c684c4", KEYUTIL.getKey(pem));
    }
    function get_cookie_spsc_uncrypted_part() {
      return "";
    }
    function get_cookie_spsc() {
      const ret = get_cookie_spsc_uncrypted_part() + get_cookie_spsc_encrypted_part();
      return "spsc=" + ret;
    }
    

    从所有这些脚布中,我们需要负责spid和 的东西spsc。第一个是在公共领域,我们只需要把它捡起来,但第二个是通过两种方法生成的get_cookie_spsc_uncrypted_part() + get_cookie_spsc_encrypted_part()。

    让我们看看这些方法:

    • get_cookie_spsc_uncrypted_part- 那里一片空白(也许很快就会出现)。
    • get_cookie_spsc_encrypted_part- 但这里更有趣的是,变量 中有一个私钥pem,并且还使用 解密了某个长字符串KJUR.crypto.Cipher.decrypt(...);。在这里,如果我们在互联网上稍微搜索一下,我们就会了解到某个字符串是用某个 RSA 密钥进行编码的,并且要重复这些操作,我们需要密钥本身和相应编码的字符串。

    以编程方式收集数据

    分析完了,现在让我们来看看吧。在这个阶段我们已经有了 HTML,我们需要从中提取我们需要的内容,问题是如何提取?最简单的方法是Regex,但是如果您解析 HTML,那么您很可能有一种特殊的方法。此方法的库。为了简单起见,我将使用 bare Regex。我将其添加到上面的代码中:

    var spid = Regex.Match(html, @"spid=(.*)"";").Groups[1].Value;
    var pemKey = Regex.Match(html, "-----BEGIN RSA PRIVATE KEY-----[\\s\\S]*?-----END RSA PRIVATE KEY-----").Value;
    var encryptedDataHex = Regex.Match(html, @"KJUR.crypto.Cipher.decrypt\(""(.*)""").Groups[1].Value;
    

    顺便说一句,我注意到该网站并不总是给出以 开头的密钥BEGIN RSA PRIVATE KEY,有时它给出的密钥没有RSA( BEGIN PRIVATE KEY)。我在这里没有考虑到这一点,但你应该考虑。

    这段代码最终应该从 HTML 站点“剥离”我们需要的所有数据。还剩下一点点要做。

    Cookie解密与生成

    嗯,这里一切都很简单。

    • 我们创造RSA——using var rsa = RSA.Create();
    • 我们将密钥导入其中Pem-rsa.ImportFromPem(pemKey);
    • 将十六进制字符串转换为字节数组 -var encryptedData = Convert.FromHexString(encryptedDataHex);
    • 破译——var decryptedData = rsa.Decrypt(encryptedData, RSAEncryptionPadding.Pkcs1);
    • 我们从结果字节数组中形成一个字符串 -var spsc = Encoding.UTF8.GetString(decryptedData);

    所有代码:

    using var rsa = RSA.Create();
    rsa.ImportFromPem(pemKey);
    var encryptedData = Convert.FromHexString(encryptedDataHex);
    var decryptedData = rsa.Decrypt(encryptedData, RSAEncryptionPadding.Pkcs1);
    var spsc = Encoding.UTF8.GetString(decryptedData);
    

    我们再次发送请求

    我们已经成功收到了我们需要的Cookie,剩下的就是在新的请求中发送它们:

    client.DefaultRequestHeaders.Add("Cookie", $"spid={spid}; spsc={spsc}");
    html = await client.GetStringAsync(url);
    

    Aaand...本站已成功提供数据,恭喜!

    整个代码如下所示:

    private static readonly HttpClient client = new();
    
    static async Task Main(string[] args)
    {
        client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36");
    
        var url = "https://www.perekrestok.ru/cat/c/104/rastitelnoe-maslo";
        var html = await client.GetStringAsync(url);
    
        var spid = Regex.Match(html, @"spid=(.*)"";").Groups[1].Value;
        var pemKey = Regex.Match(html, "-----BEGIN RSA PRIVATE KEY-----[\\s\\S]*?-----END RSA PRIVATE KEY-----").Value;
        var encryptedDataHex = Regex.Match(html, @"KJUR.crypto.Cipher.decrypt\(""(.*)""").Groups[1].Value.Trim();
    
        using var rsa = RSA.Create();
        rsa.ImportFromPem(pemKey);
        var encryptedData = Convert.FromHexString(encryptedDataHex);
        var decryptedData = rsa.Decrypt(encryptedData, RSAEncryptionPadding.Pkcs1);
        var spsc = Encoding.UTF8.GetString(decryptedData);
    
        client.DefaultRequestHeaders.Add("Cookie", $"spid={spid}; spsc={spsc}");
        html = await client.GetStringAsync(url);
    }
    

    工作示例:dotnetfiddle

    • 7

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5