使用node.js+puppeteer 实现一次稍微复杂的爬虫

使用node.js+puppeteer 实现一次稍微复杂的爬虫

1.一些方法的说明均在代码中有注释

const puppeteer = require('puppeteer');

const fs = require('fs');

const  userAgents = require('./userAgents.js');


(async ()=>{
	//代理地址
	let proxy = '127.0.0.1:8888';
	
	//创建 操作浏览器的 对象(木偶人)
	let browser = await puppeteer.launch({
		headless:false,
		args: [
     `--proxy-server=${proxy}`, // Charles proxy   设置代理
     ]	
	});
	
	try{
		// 打开浏览器
		const page = await browser.newPage();
		
		//将拦截请求的开关  开启          设置为true 之后  就可以 监听 request  和 response 事件    可以拦截 请求 和请求响应 
		await page.setRequestInterception(true);
		
		//设置 request 监听事件  (只要有请求发送就会触发)       
		page.on('request', interceptedRequest => {
			//判断如果是 图片请求  就直接拦截  
		    if (interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.jpg'))
		      interceptedRequest.abort();   //终止请求
		    else
		      interceptedRequest.continue();//弹出
		});
		
		// 数据爬取 主要逻辑
		//数据最终存储 的数组
		const array=[];
		
		//进入 亚马逊 搜索页面
		await page.goto('https://www.amazon.cn/?nocache=1551401627147',{timeout:300000});
		
		//选择出 搜索框
		const search = await page.$('#twotabsearchtextbox');
		
		//输入 iphonex
		await search.type('ipad');
		
		//选择出 查询按钮
		const searchSubmit = await page.$('#nav-search > form > div.nav-right > div > input');
		
		//点击查询
		await searchSubmit.click();
		
		//等待2.5s
 		await page.waitFor(2500);
 		
 		//获取当前 搜索结果页 路径
 		let searchResult = await page.evaluate(()=>{return document.URL;});
		
		console.log('结果页面',searchResult);
 		
 		//商品页面  下一页按钮
 		let searchResultNext = '';
 		
 		//下一页按钮路径
 		let searchResultNextUrl= '';
 		
 		//获取商品搜索结果 页面 下一页按钮
 		searchResultNext = await page.$('#pagnNextLink');
		
		while(1){
			//获取当前页的所有商品 链接
			console.log('运行');
			
			//等待2s执行
			await page.waitFor(2000);
			
			//获取当前页面的所有商品 
			const firstGoods = await page.$$('li > div > div.a-row.a-spacing-base > div > div > a');
				
			console.log('商品数量',firstGoods.length);
			
			for(let i=0;i<firstGoods.length;i++){
				//每次获取完一个店铺 之后 回到 搜索结果页面  重新获取 所有 商品链接
				let goods = await page.$$('li > div > div.a-row.a-spacing-base > div > div > a');
				//将goods 转化为 数组    (之前是类数组)
				goods = Array.from(goods);
				
				let arr=[];
				
				let item = goods[i];
				//获取商品链接				
				let  goodsUrl = await page.evaluate((item)=>{return item.href;},item);
				
				//跳转到 该商品地址
				await page.goto(goodsUrl,{timeout:300000});
				
				//等待 1 s 
				await page.waitFor(1000);
				//获取店铺名称标签
				const store = await page.$('#ddmMerchantMessage > a');
				
				//获取店铺名称
				const storeName = await page.evaluate((store)=>{return store ? store.innerHTML:'';},store)
				
				console.log('获取店铺名store');
				
				//获取包含 商品评分信息的元素  
				const grade = await page.$('#acrPopover > span.a-declarative > a > i.a-icon.a-icon-star.a-star-4-5 > span');
				
				// 获取 商品评分
				const gradeNumber = await page.evaluate((grade)=>{return grade? grade.innerHTML:''},grade);
				
				console.log('获取评分gradeNumber');
				
				//等待 2.5s
				await page.waitFor(2500);
				
				
				//获取店铺 中  查看所有评论的按钮
				const goodsAllMessagePage = await page.$('#reviews-medley-footer > div.a-row.a-spacing-large > a');
				
				console.log('goodsAllMessagePage');
				
				//判断当前 店铺 该商品 是否有评论
				if(goodsAllMessagePage){
					//获取 查看所有评论 元素
					const address = await page.evaluate((goodsAllMessagePage)=>{return goodsAllMessagePage.href;},goodsAllMessagePage);
					
					//等待1s
					await page.waitFor(1000);
					
					//跳转到 所有评论页面
					await page.goto(address,{timeout:300000});
					
					while(1){
						//所有评论  页面的    下一页按钮
						const  messageNextPage = await page.$('li.a-last > a');
						
						//调用 getData 获取当前页的数据
						await getData(arr);
						
						//模拟 点击跳转
						if(messageNextPage){
							await messageNextPage.click();
							console.log('点击商品评价下一页');
						}else{
							break;
						}
						console.log('还在获取数据');
						await page.waitFor(5000);//休息5s 防止淘宝发现我们是机器人
					}
				}
				
				//生成每个店铺的信息
				let storeObj={
					storeName:storeName,
					grade:gradeNumber,
					message:JSON.stringify(arr)
				}
				//放入数组
				array.push(storeObj);
				
				console.log('所有数据数量:',array.length);
				
				await page.goto(searchResult,{timeout:300000});
			}
			
			console.log('本商品评论获取完毕');
			
			if(searchResultNext){
				//获取 搜索结果 下一页 元素
				searchResultNext = await page.$('#pagnNextLink');
 		
 				//获取搜索结果 下一页 的 路径
		 		searchResultNextUrl = await page.evaluate((searchResultNext)=>{return searchResultNext.href;},searchResultNext);
		 		
		 		//跳转到 搜索结果 页面 
		 		await page.goto(searchResultNextUrl,{timeout:300000});
		 		
		 		//等待 2s
		 		await page.waitFor(2000);
		 		
		 		//更新 搜索结果页面的路径
		 		searchResult = await page.evaluate(()=>{return document.URL;});
		 		
		 		console.log('更新翻页的搜索结果页面',searchResult);
		 		//随机更换  user-agent
				await page.setUserAgent(userAgents[Math.floor(Math.random()*userAgents.length)]);
			}else{
				break;
			}
		}
		
		await fs.writeFile('index.json',JSON.stringify(array),()=>{
			console.log('写入成功!');
		})
		//关闭浏览器
		await browser.close();
		//找到当前页的所有商品链接
		
		async function getData(arr){
			//在当前页面执行脚本
			const list = await page.evaluate(()=>{
				let alist = []
				//获取所有的商品
				let pageGoods = document.querySelectorAll('#cm_cr-review_list>div.review');
				
				for(let items of pageGoods){
					let data={
						message:'',//商品评价
					}
					//获取商品评价 
					const message = items.querySelector('div span[data-hook="review-body"]');
					
					data.message = message.innerHTML;
					
					alist.push(data);
				}
				return alist;
			})
			list.forEach(item=>{
				arr.push(item);
			})
			console.log('数组长度:',list.length);
		}
		
		
	}catch(e){
		console.log('出错了!');
		console.log(e);
	}
	
})()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值