多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Peacock Team 爬虫测试任务实战:用 Puppeteer 采集 Avito 广告列表并输出 JSON

Peacock Team 爬虫测试任务实战:用 Puppeteer 采集 Avito 广告列表并输出 JSON 教程【免费下载链接】ru-test-assignmentsТестовые задания для самостоятельного выполнения от разных it компаний项目地址https://gitcode.com/gh_mirrors/ru/ru-test-assignments点击查看免费下载导读本篇文章围绕 ru-test-assignments 仓库中 Peacock Team 的爬虫测试任务scrapping.md展开使用 Node.js 与 Puppeteer 编写一个无头浏览器爬虫从 Avito 的类目列表页抓取全部广告标题、描述、链接、价格、作者、发布时间、联系电话最终导出为结构化的 JSON 文件。读完本文你将掌握一个可运行的 Puppeteer 爬虫骨架、广告数据字段的建模方式以及真实列表页抓取中常见的反爬、等待与数据清洗问题。任务原文与核心需求仓库中 scrapping.md 给出了原始任务描述原文为俄语本地副本标注来源为 PeacockTeam/new-job编写一个基于 Puppeteer 的 node-js 脚本用于收集 Avito 上的广告。需求可拆解为三部分输入一个 Avito 广告列表页的 URL例如任务中给出的猫类目链接https://www.avito.ru/sankt-peterburg/koshki/poroda-meyn-kun-ASgBAgICAUSoA5IV。这类链接遵循 Avito 的通用路径结构https://www.avito.ru/{城市}/{类目}/{子类目}-{标识}仓库中其他 Avito 相关任务也印证了这一 URL 模式例如 shopx-qa-trainee.md 中的https://www.avito.ru/sochi/lichnye_veschi?cd1d1。处理以该 URL 为入口启动浏览器抓取逐条解析列表中的广告卡片。输出一个 JSON 文件内容为广告对象组成的数组。Advert 数据模型八字段 JSON 结构任务用 TypeScript 接口明确规定了输出对象的字段契约这是整份文档最核心的交付标准必须逐字段实现interface Advert { title: string; // 广告标题 description: string; // 广告描述 url: string; // 广告详情页链接 price: number; // 价格数值类型非格式化字符串 author: string; // 发布者名称 date: string; // 发布时间ISO-8601 格式 phone: string; // 联系电话 }字段级实现要点字段类型采集难点与建议titlestring通常位于卡片标题节点直接取文本即可注意去除多余空白descriptionstring可能被截断为描述前几行可先采集卡片内文本详情页抓取作为增强项urlstring卡片标题链接的href注意 Avito 链接常为相对路径需用new URL(href, baseUrl).toString()补全为绝对地址pricenumber页面显示的是带货币符号与分隔符的文本如45 000 ₽必须清洗先replace(/[^\d]/g, )再parseInt否则无法通过number类型校验authorstring卡片作者区文本可能包含продавец等附属文字需按实际情况裁剪datestring页面常见相对时间如сегодня、вчера、3 дня назад需转换为真实日期并toISOString()输出phonestring列表页通常不直接展示完整号码需要点击Показать телефон按钮或进入详情页后从 DOM 读取是全任务中不确定性最高的字段设计数据模型而非硬编码在真实工程中建议用 TypeScript 编写脚本把上述interface Advert直接作为数据模型使用并定义类型守卫function isAdvert(item: unknown): item is Advert { const a item as Advert; return typeof a.title string typeof a.price number typeof a.url string; }这样在JSON.stringify之前即可过滤掉解析失败的残缺记录保证输出文件的字段完整性。Puppeteer 技术选型为什么是无头浏览器任务要求基于 Puppeteer原因在于 Avito 这类页面是重度 JavaScript 渲染的 SPA/动态页面普通 HTTP 请求如fetch/axios只能拿到 HTML 骨架广告卡片由前端异步渲染直接请求拿不到数据Puppeteer 驱动完整 Chromium可以执行页面脚本、等待网络与渲染完成、模拟点击如展开电话号码与真人浏览器行为一致Puppeteer 提供page.waitForSelector、page.waitForNetworkIdle等等待原语是处理动态列表页的关键能力。工程搭建与基础脚本1. 初始化项目并安装依赖mkdir avito-scraper cd avito-scraper npm init -y npm install puppeteer # 若使用 TypeScript 编写任务中数据结构用 TS 声明 npm install --save-dev typescript types/node说明puppeteer首次安装会自动下载对应版本的 Chromium在服务器/容器环境可改用puppeteer-core并自行指定executablePath。2. 最小可运行骨架import puppeteer, { Browser, Page } from puppeteer; import fs from fs/promises; const TARGET_URL process.argv[2] ?? https://www.avito.ru/sankt-peterburg/koshki/poroda-meyn-kun-ASgBAgICAUSoA5IV; async function scrape(url: string): PromiseAdvert[] { const browser: Browser await puppeteer.launch({ headless: new }); try { const page: Page await browser.newPage(); await page.goto(url, { waitUntil: networkidle2, timeout: 60_000 }); // 等待广告卡片容器出现保证 DOM 已渲染 await page.waitForSelector([data-markeritem], { timeout: 30_000 }); const adverts await page.evaluate(() { const cards Array.from(document.querySelectorAll([data-markeritem])); return cards.map((card) { // 以下选择器基于 Avito 常见 DOM 结构需按目标页面实际情况调整 const title card.querySelector([data-markeritem-title])?.textContent?.trim() ?? ; const href card.querySelector(a[data-markeritem-title])?.getAttribute(href) ?? ; const priceText card.querySelector([data-markeritem-price])?.textContent ?? ; const author card.querySelector([data-markeritem-seller-info])?.textContent?.trim() ?? ; return { title, description: , url: new URL(href, window.location.origin).toString(), price: parseInt(priceText.replace(/[^\d]/g, ), 10) || 0, author, date: , phone: , }; }); }); return adverts; } finally { await browser.close(); } } async function main() { const data await scrape(TARGET_URL); await fs.writeFile(adverts.json, JSON.stringify(data, null, 2), utf-8); console.log(Saved ${data.length} adverts to adverts.json); } main().catch((err) { console.error(err); process.exit(1); });3. 命令行使用方式node dist/scraper.js https://www.avito.ru/sankt-peterburg/koshki/poroda-meyn-kun-ASgBAgICAUSoA5IV脚本读取第一个命令行参数作为入口链接输出adverts.json。这正好对应任务中输入为列表页链接、输出为 JSON 文件的闭环。关键难点的工程化处理相对时间转 ISO-8601列表页的date常为俄语相对时间。稳妥做法是不依赖列表页文本而是进入详情页读取time元素的datetime属性通常已是 ISO-8601或者维护一张相对时间映射表function parseRelativeDate(text: string): string | { const now new Date(); if (/сегодня/.test(text)) return now.toISOString(); if (/вчера/.test(text)) { now.setDate(now.getDate() - 1); return now.toISOString(); } const match /(\d)\sдня?/.exec(text); if (match) { now.setDate(now.getDate() - parseInt(match[1], 10)); return now.toISOString(); } return ; // 无法解析时留空而非编造 }原则解析失败的字段置空字符串绝不在数据层面伪造时间。电话字段模拟点击展开Avito 列表页默认隐藏完整号码需点击Показать телефон类按钮后号码才会注入 DOM。实现上可对每个卡片执行await page.$$eval([data-markeritem], async (cards) { // 逐卡点击展开按钮并等待号码节点出现 });这一步涉及真实页面交互与网络请求最易触发风控是本任务中验证可运行性的关键务必在提交前实测。分页与完整采集任务未明确要求翻页但收集广告的语义通常包含多页。可在列表页底部查找下一页链接并循环抓取用page.url()变化或页码节点判停最终将多页结果concat后一次性写入 JSON。合理使用等待避免无谓反爬使用waitUntil: networkidle2或waitForSelector而非固定setTimeout在两次请求之间加入随机延迟模拟人类浏览节奏复用同一个 Browser 实例、控制并发页面数量避免瞬间高频请求导致 IP 被限制。与仓库内其他 Avito 任务的印证本仓库中与 Avito 相关的其他测试任务可帮助理解该站点的页面特性与评估维度shopx-qa-trainee.md要求对 avito.ru 编写端到端自动化测试并明确指出本地运行时会出现验证码капча验证将在测试服务器进行——这直接印证了爬虫任务中反爬措施的存在说明脚本设计时应预见到验证码与风控场景shopx-qa-trainee.md 要求使用 PageObject 模式组织自动化代码——同样适用于爬虫工程建议把页面选择器封装为独立模块方便站点改版后快速维护auto-backend-trainee-assignment.mdAvito 后端任务同一站点的另一技术方向展示了 Avito 系任务对交付质量的通用要求提供启动说明、代码托管、测试覆盖70%。自测与交付清单完成任务后请按以下清单自检对应 scrapping.md 的验收标准可运行node运行脚本输入示例链接能正常产出adverts.json结构合规JSON 顶层为数组每个元素恰好包含title / description / url / price / author / date / phone七个字段类型与interface Advert一致重点检查price为数字、date为 ISO-8601数据真实抽样比对页面展示内容与输出文件确认无乱码、无错位字段容错单条卡片解析失败不影响整体输出跳过或标记为空文档完整参照同目录其他任务如 devops-ansible.md 要求附运行命令与结果截图在 README 中写明依赖安装、启动命令与运行结果截图。结语这份来自 Peacock Team 的爬虫任务虽然篇幅简短却浓缩了爬虫工程的核心链路URL 入口 → 无头浏览器渲染 → DOM 解析 → 字段清洗 → JSON 落地。以 scrapping.md 的数据契约为基准结合 Puppeteer 的等待、点击与求值能力即可在本地复现一个面向 Avito 列表页的可运行采集器。后续如需增强可在此基础上扩展详情页抓取、代理轮换与增量去重将脚本演进为生产级采集管线。赞分享教程【免费下载链接】ru-test-assignmentsТестовые задания для самостоятельного выполнения от разных it компаний项目地址https://gitcode.com/gh_mirrors/ru/ru-test-assignments点击查看免费下载相关推荐Market Intelligence 测试任务实战用 Python 构建 Avito 广告数量监控 JSON API 服务Market Intelligence 测试任务实战用 Python 构建 Avito 广告数量监控 JSON API 服务 导读 本篇技术指南围绕仓库中 b教程Avito iOS 实习生测试任务实战用 Swift URLSession 构建单屏 JSON 列表应用Avito iOS 实习生测试任务实战用 Swift URLSession 构建单屏 JSON 列表应用 本篇技术指南围绕 Avito 2021 年 iO教程Avito Tech iOS 实习测试任务实战指南从 JSON 解析到 UICollectionView 单选列表实现Avito Tech iOS 实习测试任务实战指南从 JSON 解析到 UICollectionView 单选列表实现 本指南围绕 Avito Tech 的教程上一篇从OSI到Apache Ossie一段语义元数据交换标准化的演进史下一篇Apache Beam 中的 ParquetIO 指南使用 ReadFromParquet / WriteToParquet 读写 Parquet 文件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表