木偶师

编程入门 行业动态 更新时间:2024-10-05 15:35:00

<a href=https://www.elefans.com/category/jswz/34/1770299.html style=木偶师"/>

木偶师

我正在使用 Puppeteer 来绕过 cloudflare 安全性。
长话短说,我需要执行一个

POST
请求来启动某种二进制文件下载。实际上,这个文件只是一个纯文本,由于某种原因而没有像这样发送扩展名(由
\n
分隔)
并且可以使用任何文本编辑器轻松打开:

{ json string 1 }
{ json string 2 }
...

W当普通浏览器执行此请求时(当站点按应有的方式使用时),它只是获取此 url,等待它的响应,并且文本正在页面上显示。在 DevTools 中可以将响应本身视为带有

application/octet-stream
标题的纯文本。
W当我尝试使用
GoToAsync
non-headless 模式下使用 Puppeteer 获取它时,它等待响应,然后开始使用 chromium 下载管理器将其作为二进制文件下载,并且在下载完成之前,立即抛出
NavigationException: net::ERR_ABORTED
,但下载继续正常进行。没关系,我知道这只是某种错误,我实际上仍然可以用
try-catch
处理它,然后通过打开下载的文件访问接收到的数据(不过,最好把它作为一个
 Stream
或响应本身的纯文本)
.
P问题是我需要在 headless 模式下使用 Puppeteer。在 headless 中,它的行为完全相同,但下载不会开始。我能用它做什么?我至少可以以某种方式下载它,以与非无头模式相同的方式忽略此异常吗?

这是我使用的示意性代码示例:

var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
var browser = await Puppeteer.LaunchAsync(new() { Headless = true });
var page = await browser.NewPageAsync();

await page.SetRequestInterceptionAsync(true);
await page.Client.SendAsync("Page.setDownloadBehavior", new
{
    behavior = "allow",
    downloadPath = "_path_"
});

page.Request += async (s, e) =>
{
    // sets method to POST, adds some headers, specifies post-data
    var payloadOverride = new Payload() { ... };
    await e.Request.ContinueAsync(payloadOverride); // executes normally and leaves code block
};

var response = await page.GoToAsync($"url"); // will throw exception "somewhere in await"

此外,我尝试做这样的事情:

page.Response+= async (s, e) =>
{
    await e.Response.TextAsync();
    await e.Response.JsonAsync();
    await e.Response.BufferAsync();
};

GoToAsync
时,
.Response
事件实际上被正常触发(就在
net::ERR_ABORTED
抛出之前)
,但是这些方法只会抛出
PuppeteerSharp.BufferException: "Unable to get response body"
。所以,我无法像我希望的那样从这里获取数据。

此外,我尝试使用

Evaulate
从浏览器本身对它进行
fetch()
,但 cloudflare 不允许我这样做。虽然,它 (
fetch(...).then((response) => response.text())
) 在我的普通浏览器的控制台中工作,并成功返回预期的文本字符串,如本主题开头的示例,但前提是我首先访问该站点本身并在那里打开 DevTools。我试过用 Puppeteer
GoTo
到它,然后
Evaulate
它在那里,但是 1020 Access Denied.
几周前,在 cloudflare 更新某些东西之前,我只是简单地使用
HttpClient
和适当的用户代理标头。这段代码看起来像这样并且工作得非常好:

HttpRequestMessage request = new(HttpMethod.Post, "same url");
// ...setting post-data and headers...
var response = await _httpClient.SendAsync(request);

// => It will return simple text with few lines, as in example in beginning
string content = await response.Content.ReadAsStringAsync();
string[] chunks = content.Split("\n"); // => and here I have array of JSON string ["{ }", "{ }", ...]

如有任何建议,我们将不胜感激。我使用 Puppeteer 的

.NET
版本,但是如果您的示例将使用
JS
编写就可以了,因为我知道节点版本更受欢迎。

回答如下:

到目前为止我找到的解决方案: 第一的: 只需在

Puppeteer Stealth Plugin
中使用
fetch()
和 JS
EvaluateFunctionAsync()
。是的,就这么简单。

第二: 这就是我在知道隐形插件之前使用的东西。

string someDownloadPath = "";
var page = await _browser.NewPageAsync();
await page.SetRequestInterceptionAsync(true);

// allows regular downloads for a headless mode
await page.Client.SendAsync("Page.setDownloadBehavior", new { behavior = "allow", someDownloadPath });

// sending POST with GoToAsync
page.Request += (s, requestArgs) => YourContinueRequestHandler(requestArgs, HttpMethod.Post, data);

// it will ALWAYS throw an exception
try { await page.GoToAsync(url); }
catch (NavigationException)
{
    // puppeteer will download content as a binary file with a "download" name
    string responsePath = $"{someDownloadPath}/download";

    // Wait 30 seconds for a response to download
    for (int i = 0; i < 15; i++)
    {
        await Task.Delay(2000);
        if (File.Exists(responsePath)) break;
    }
    var content = await File.ReadAllTextAsync(responsePath);
}

更多推荐

木偶师

本文发布于:2024-05-28 11:20:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1770133.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:木偶

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!