- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
作为个人挑战,我正在尝试创建一个工具,该工具将使用Puppeteer抓取网站(本实验所使用的购物平台AliBaba)的搜索结果,并将输出保存到JSON对象中,以便以后用于创建前端的可视化。
我的第一步是访问搜索结果的第一页,并将列表从那里刮到一个数组中:
const puppeteer = require('puppeteer');
const fs = require('fs');
/* First page search URL */
const url = (keyword) => `https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&CatId=&SearchText=${keyword}`
/* keyword to search for */
const keyword = `future`;
(async () => {
try {
const browser = await puppeteer.launch({
headless: true
});
const page = await browser.newPage();
await page.goto(url(keyword), {
waitUntil: 'networkidle2'
});
await page.waitForSelector('.m-gallery-product-item-v2');
let urls = await page.evaluate(() => {
let results = [];
let items = document.querySelectorAll('.m-gallery-product-item-v2');
// This console.log never gets printed to either the browser window or the terminal?
console.log(items)
items.forEach( item => {
let CurrentTime = Date.now();
let title = item.querySelector('h4.organic-gallery-title__outter').getAttribute("title");
let link = item.querySelector('.organic-list-offer__img-section').getAttribute("href");
let img = item.querySelector('.seb-img-switcher__imgs').getAttribute("data-image");
results.push({
'scrapeTime': CurrentTime,
'title': title,
'link': `https:${link}`,
'img': `https:${img}`,
})
});
return results;
})
console.log(urls)
browser.close();
} catch (e) {
console.log(e);
browser.close();
}
})();
当我使用Node在终端中运行文件(test-2.js)时,它有时会返回
results
数组,但有时会抛出错误。大约一半时间抛出的终端错误是:
Error: Evaluation failed: TypeError: Cannot read property 'getAttribute' of null
at __puppeteer_evaluation_script__:11:82
at NodeList.forEach (<anonymous>)
at __puppeteer_evaluation_script__:8:19
at ExecutionContext._evaluateInternal (/Users/dmnk/scraper/node_modules/puppeteer/lib/ExecutionContext.js:102:19)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async ExecutionContext.evaluate (/Users/dmnk/scraper/node_modules/puppeteer/lib/ExecutionContext.js:33:16)
at async /Users/dmnk/scraper/test-2.js:24:20
-- ASYNC --
at ExecutionContext.<anonymous> (/Users/dmnk/scraper/node_modules/puppeteer/lib/helper.js:94:19)
at DOMWorld.evaluate (/Users/dmnk/scraper/node_modules/puppeteer/lib/DOMWorld.js:89:24)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
-- ASYNC --
at Frame.<anonymous> (/Users/dmnk/scraper/node_modules/puppeteer/lib/helper.js:94:19)
at Page.evaluate (/Users/dmnk/scraper/node_modules/puppeteer/lib/Page.js:612:14)
at Page.<anonymous> (/Users/dmnk/scraper/node_modules/puppeteer/lib/helper.js:95:27)
at /Users/dmnk/scraper/test-2.js:24:31
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:53159) UnhandledPromiseRejectionWarning: ReferenceError: browser is not defined
at /Users/dmnk/scraper/test-2.js:52:9
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:53159) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:53159) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
我对掌握和学习异步JavaScript相对较新。
最佳答案
实际上,您确实滥用了异步JavaScript,这会导致脚本失败。对于互联网连接速度稍慢的我来说,Evaluation failed: TypeError: Cannot read property 'getAttribute' of null
错误始终存在。通过将 networkidle2
中的domcontentloaded
替换为page.goto
waitUntil设置,您可以稍微提高稳定性(请确保阅读文档之间有什么区别)。
主要问题是异步事件(与chrome api的通信)未等待。您可以考虑以下几点开始重构脚本:
更有效地选择元素
const
以避免意外覆盖已选择的元素。 page
上下文标识元素。 Puppeteer(chrome)还为$$
提供了querySelectorAll
别名; $
:querySelector
。 (docs) await
异步事件,一切都被认为是异步的,需要与chrome api进行通信! let items = document.querySelectorAll('.m-gallery-product-item-v2');
之后:
const items = await page.$$('.m-gallery-product-item-v2');
.getAttribute
):
let title = item.querySelector('h4.organic-gallery-title__outter').getAttribute("title");
之后:
const title = await page.evaluate(el => el.title, (await page.$$('h4.organic-gallery-title__outter'))[i])
forEach
遍历异步事件
forEach
循环中使用async/await。但是,实际上,缺少异步是如果未及时加载页面导致脚本失败的原因。您确实需要异步,只是不需要在
forEach
内(不,也不需要在
Array.map
内!)。我宁愿建议
使用 for...of
或常规的for循环,如果您希望使用伪造者 Action 进行可预测的行为。 (在当前示例中,数组索引具有关键部分,因此为了简单起见,我使用了for循环)
forEach
,但是您需要使用
Promise.all
对其进行包装。
page.evaluate
部分使代码保持异步,但是您也可以通过使用上面的建议并等待每个步骤来解决此问题。您最终都不会返回
results
对象,但是可以在循环的每次迭代中填充它。
console.log(items);
也将被记录到控制台。
const puppeteer = require('puppeteer');
/* first page search URL */
const url = keyword => `https://www.alibaba.com/trade/search?fsb=y&IndexArea=product_en&CatId=&SearchText=${keyword}`;
/* keyword to search for */
const keyword = 'future';
const results = [];
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto(url(keyword), { waitUntil: 'domcontentloaded' });
await page.waitForSelector('.m-gallery-product-item-v2');
const items = await page.$$('.m-gallery-product-item-v2');
// this console.log never gets printed to either the browser window or the terminal?
console.log(items);
for (let i = 0; i < items.length; i++) {
try {
let CurrentTime = Date.now();
const title = await page.evaluate(el => el.title, (await page.$$('h4.organic-gallery-title__outter'))[i]);
const link = await page.evaluate(el => el.href, (await page.$$('.organic-list-offer__img-section, .list-no-v2-left__img-container'))[i]);
const img = await page.evaluate(el => el.getAttribute('data-image'), (await page.$$('.seb-img-switcher__imgs'))[i]);
results.push({
scrapeTime: CurrentTime,
title: title,
link: `https:${link}`,
img: `https:${img}`
});
} catch (e) {
console.error(e);
}
}
console.log(results);
await browser.close();
} catch (e) {
console.log(e);
await browser.close();
}
})();
编辑:该脚本有时会失败,因为在阿里巴巴的网站上
.organic-list-offer__img-section
CSS类已更改为
.list-no-v2-left__img-container
。他们要么AB用不同的选择器测试两个布局,要么经常更改CSS类。
const link = await page.evaluate(el => el.href, (await page.$$('.organic-list-offer__img-section, .list-no-v2-left__img-container'))[i]);
这将确保在两种情况下都可以选择该元素,
comma的作用类似于
OR
运算符。
关于javascript - puppeteer : Scrape sometimes works, sometimes fails with TypeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62516119/
虽然 HTML Scraping 从我所看到的内容中得到了很好的记录,并且我了解它的概念和实现,但是从隐藏在身份验证表单后面的内容中进行抓取的最佳方法是什么。我指的是从我合法访问的内容中抓取,因此我正
使用 Python、Selenium、Sublime 和 Firefox:我正在从这个网站上抓取链接,并想将抓取的页面(作为 html 文件)保存到一个文件夹中。但是,我已经工作了好几天,试图将这些
我需要构建一个 python 脚本,旨在抓取网页以检索“显示更多”按钮中的数字。 此数字将用作请求 URL 的参数,该 URL 将返回包含数据 + 数字的 JSON。最后一个数字将用作请求 URL 的
当 Google map 在某种程度上确认某个地点搜索时,它会重定向到特定的 Google 地点 url,否则它会返回 map 搜索结果页面。 谷歌地图搜索“manarama”是 https://ww
每当我想在 amazon.com 上抓取时,我都会失败。因为产品信息会根据 amazon.com 中的位置而变化 这个变化信息如下; 1-价格 2-运费 3-海关费用 4-发货状态 用selenium
我正在使用scrapy来抓取网站,现在我需要设置代理处理已发送的请求。谁能帮我在scrapy应用程序中解决这个设置代理。如果有,也请提供任何示例链接。我需要解决这个请求来自哪个 IP 的问题。 最佳答
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 2年前关闭。 Improve thi
我想知道是否有任何技术可以识别收集信息以供非法使用的网络爬虫。通俗地说,数据盗窃是为了创建一个网站的副本。 理想情况下,该系统会检测来自未知来源的抓取模式(如果 Google 抓取工具不在列表中,等等
我想编写一个抓取脚本来检索cnn文章中的评论。例如,本文:http://www.cnn.com/2012/01/19/politics/gop-debate/index.html?hpt=hp_t1
我正在尝试构建Instagram帐户的Microsoft Access数据库,并希望提取以下数据以及其他信息: 帐户名 关注者数量 关注的人数 帖子数(及其日期) 图片的赞数 图片上的评论数量 我在构
我正在尝试运行一个爬虫,其输出日志如下所示: 2017-04-25 20:22:22 [scrapy.spidermiddlewares.httperror] INFO: Ignoring respo
我想抓取一个网站,该网站的网页上有他们商店的所有联系方式,我可以手动记下这些信息,因此抓取该网站是合法的还是非法的。 最佳答案 是的,除非您不道德地使用它。 Web 抓取就像世界上的任何工具一样。您可
假设我有以下 html: I am going by flying mr tt 文本节点中任何等于或大
寻找任何工具(最好在 python 中)来提取特定网页收到的浏览次数。如果没有,也很方便知道我是否可以获得任何其他网页特定的分析(例如列出的那个) 最佳答案 除非您拥有此特定网页,否则无法查看它获得了
我刚刚开始研究这个,我想将我的 Netgear 路由器 ( http://192.168.0.1/setup.cgi?next_file=stattbl.htm ) 统计数据刮到一个 csv 文件中。
我目前是开发包含前端客户端的应用程序的团队的一员。 我们通过这个客户端发送用户数据,每个用户都有一个用户 ID,客户端通过 RESTful API 与我们的服务器对话,向服务器询问数据。 例如,假设我
有谁知道我如何轻松下载所有已发表的文章摘要?我正在做一个文本挖掘项目。 我能找到的最接近的一个可以在给定 pmid 的情况下一次下载一个摘要,但这对我的目的来说太慢了,因为我必须一次下载一个。 最佳答
当我使用Beautiful Soup发出请求时,我被阻止为“机器人”。 import requests from bs4 import BeautifulSoup reddit1Link = requ
由于网站抓取 Google、Bing 等违反了他们的服务条款,我想知道是否有任何搜索引擎可以抓取结果? 最佳答案 为什么要刮?为什么不使用支持的 API? http://code.google.com
许多页面(facebook、google+ 等)都有一个功能,可以创建带有标题、图像和来自链接的一些文本的摘要。我试图找出是否有任何关于如何执行此类功能的库或指南,但我的搜索结果根本没有帮助。 我知道
我是一名优秀的程序员,十分优秀!