我正在尝试使用PuppeteerCrawler抓取我们的本地Confluence安装。我的策略是首先登录,然后提取会话cookie并在起始URL的标题中使用它们。代码如下:
首先,我“徒步”登录以提取相关凭据:
const Apify = require("apify");
const browser = await Apify.launchPuppeteer({sloMo: 500});
const page = await browser.newPage();
await page.goto('https://mycompany/confluence/login.action');
await page.focus('input#os_username');
await page.keyboard.type('myusername');
await page.focus('input#os_password');
await page.keyboard.type('mypasswd');
await page.keyboard.press('Enter');
await page.waitForNavigation();
// Get cookies and close the login session
const cookies = await page.cookies();
browser.close();
const cookie_jsession = cookies.filter( cookie => {
return cookie.name === "JSESSIONID"
})[0];
const cookie_crowdtoken = cookies.filter( cookie => {
return cookie.name === "crowd.token_key"
})[0];
然后我正在使用准备好的请求标头构建爬虫结构:
const startURL = {
url: 'https://mycompany/confluence/index.action',
method: 'GET',
headers:
{
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
Cookie: `${cookie_jsession.name}=${cookie_jsession.value}; ${cookie_crowdtoken.name}=${cookie_crowdtoken.value}`,
}
}
const requestQueue = await Apify.openRequestQueue();
await requestQueue.addRequest(new Apify.Request(startURL));
const pseudoUrls = [ new Apify.PseudoUrl('https://mycompany/confluence/[.*]')];
const crawler = new Apify.PuppeteerCrawler({
launchPuppeteerOptions: {headless: false, sloMo: 500 },
requestQueue,
handlePageFunction: async ({ request, page }) => {
const title = await page.title();
console.log(`Title of ${request.url}: ${title}`);
console.log(page.content());
await Apify.utils.enqueueLinks({
page,
selector: 'a:not(.like-button)',
pseudoUrls,
requestQueue
});
},
maxRequestsPerCrawl: 3,
maxConcurrency: 10,
});
await crawler.run();
通过脚步登录和cookie提取似乎没问题(“curlified”请求工作正常),但Confluence不接受通过puppeteer / headless chromium登录。似乎标题丢失了某种方式..
我究竟做错了什么?
在没有首先详细说明标头不起作用的细节的情况下,我建议在gotoFunction
选项中定义自定义PuppeteerCrawler
,例如:
{
// ...
gotoFunction: async ({ request, page }) => {
await page.setCookie(...cookies); // From page.cookies() earlier.
return page.goto(request.url, { timeout: 60000 })
}
}
这样,您就不需要进行解析,并且在每次加载页面之前会自动将cookie注入浏览器。
请注意,在使用无头浏览器时修改默认请求标头不是一个好习惯,因为它可能会导致在某些网站上阻止匹配已知浏览器指纹列表的已接收标头。
以下部分不再相关,因为您现在可以使用Request
类按预期覆盖标头。
标题问题是一个复杂的问题涉及到Puppeteer中的request interception。 Apify SDK中的Here's the related GitHub issue。不幸的是,通过Request
对象覆盖标头的方法目前在PuppeteerCrawler
中不起作用,所以这就是你不成功的原因。