一、什么是爬虫
爬虫是一种自动化程序,用于在互联网上收集信息。它可以模拟人类用户的行为,访问网页并提取其中的数据,这些数据可以用于分析、展示或其他应用。可以把互联网比做成一张“大网”,爬虫就是在这张大网上不断爬取信息的程序。
二、手动爬虫
手动爬虫需要人工编写代码来请求网页、解析HTML并提取信息。
自动化爬虫则使用程序自动执行这些任务,通常会使用工具如Selenium或Puppeteer来模拟浏览器行为,从而实现自动化的数据收集。
在爬虫中,cheerio是一个类似于jQuery的库,用于在服务器端解析HTML文档。它提供了一种简单而强大的方式来对HTML文档进行操作和提取数据,可以通过选择器来定位和提取所需的信息,非常适合用于网页数据的抓取和处理。
案例一:爬取图片
const http =require("https");const cheerio =require("cheerio");const download =require("download");let req = http.request("https://www.csdn.net/",(res)=>{let chunks =[];
res.on("data",(chunk)=>{
chunks.push(chunk);});
res.on("end",()=>{let html = Buffer.concat(chunks).toString("utf-8");let $ = cheerio.load(html);let imgArr =Array.prototype.map.call($(".ContentBlock .ContentBlockItem img"),(item)=>encodeURI($(item).attr("src")));
console.log("imgArr", imgArr);
Promise.all(imgArr.map((x)=>download(x,"dist"))).then(()=>{
console.log("files downloaded!");});});});
req.end();
案例二:爬取文案 - 从接口获取
const https =require("https");let url ="https://img-home.csdnimg.cn/data_json/toolbar/toolbar1105.json";let req = https.request(url,{method:"get"},(res)=>{let chunks =[];
res.on("data",(chunk)=> chunks.push(chunk));
res.on("end",()=>{let result = Buffer.concat(chunks).toString("utf-8");
console.log(JSON.parse(result));});});
req.end();
如果遇到请求限制,可以模拟真实浏览器的请求头:
const https =require("https");let url ="https://img-home.csdnimg.cn/data_json/toolbar/toolbar1105.json";let req = https.request(url,{method:"get",headers:{"Host":"www.csdn.net","Connection":"keep-alive","Content-Length":"0","Accept":"*/*","Origin":"https://www.csdn.net/","X-Requested-With":"XMLHttpRequest","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36","DNT":"1","Referer":"https://www.csdn.net/?spm=1001.2101.3001.4476","Accept-Encoding":"gzip, deflate","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","Cookie":"UM_distinctid=16b8a0c1ea534c-0c311b256ffee7-e343166-240000-16b8a0c1ea689c; bad_idb2f10070-624e-11e8-917f-9fb8db4dc43c=8e1dcca1-9692-11e9-97fb-e5908bcaecf8; parent_qimo_sid_b2f10070-624e-11e8-917f-9fb8db4dc43c=921b3900-9692-11e9-9a47-855e632e21e7........ "}},(res)=>{let chunks =[];
res.on("data",(chunk)=> chunks.push(chunk));
res.on("end",()=>{let result = Buffer.concat(chunks).toString("utf-8");
console.log(JSON.parse(result));});});
req.end();
案例三:爬取图片+文本
const http =require("https");const fs =require("fs");const cheerio =require("cheerio");const download =require("download");const path =require("path");let req = http.request("https://www.csdn.net/",(res)=>{let chunks =[];
res.on("data",(chunk)=>{
chunks.push(chunk);});
res.on("end",()=>{let html = Buffer.concat(chunks).toString("utf-8");let $ = cheerio.load(html);let itemArr =Array.prototype.map.call($(".ContentBlock .ContentBlockItem"),(item)=>{return{title:$(item).find(".title").text(),img:$(item).find("img").attr("src"),};});let jsonData =JSON.stringify(itemArr,null,2);const distDir = path.join(__dirname,"dist");if(!fs.existsSync(distDir)){
fs.mkdirSync(distDir);}
fs.writeFile("dist/data.json", jsonData,(err)=>{if(err)throw err;});
Promise.all(itemArr.map((x)=>download(x.img,"dist"))).then(()=>{
console.log("Files downloaded!");});});});
req.end();
三、自动化爬虫
Web应用的自动化测试框架,可以创建回归测试来检验软件功能和用户需求,通过框架可以编写代码来启动浏览器进行自动化测试,换言之,用于做爬虫就可以使用代码启动浏览器,让真正的浏览器去打开网页,然后去网页中获取想要的信息,无惧反爬虫手段。
1、Selenium与puppeteer的对比
Selenium和Puppeteer都是用于Web自动化测试和爬虫的工具,它们之间有一些区别:
- 语言支持: - Selenium:支持多种编程语言,如Java、Python、JavaScript等。- Puppeteer:主要支持JavaScript,因为是基于Node.js开发的。
- 浏览器支持: - Selenium:支持多种浏览器,如Chrome、Firefox、Safari等。- Puppeteer:主要支持Chrome浏览器,因为是由Chrome团队开发的。
- 性能: - Puppeteer通常比Selenium更快,因为Puppeteer是直接操作Chrome浏览器而不是通过WebDriver协议来控制浏览器。
- 功能: - Puppeteer提供了更多高级功能,如截图、PDF生成、网络请求拦截等,而Selenium相对来说功能较为基础。
- 部署: - Puppeteer相对来说更容易部署,因为它是一个Node.js库,安装和配置相对简单。- Selenium需要下载相应的浏览器驱动,并配置环境变量,相对复杂一些。
总的来说,如果需要更高级的功能和更好的性能,可以选择Puppeteer;如果需要跨浏览器支持或使用其他编程语言,可以选择Selenium。
2、Selenium的使用
- 根据平台下载需要的webdriver,下载后放入项目根目录,注意: 下载的webdriver要和当前浏览器的版本一致
浏览器webdriverChromehttps://getwebdriver.com/chromedriver#stableInternetExplorerhttp://selenium-release.storage.googleapis.com/index.htmlEdgehttp://go.microsoft.com/fwlink/?LinkId=619687Firefoxhttps://github.com/mozilla/geckodriver/releases/Safarihttps://developer.apple.com/library/prerelease/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html#//apple_ref/doc/uid/TP40014305-CH11-DontLinkElementID_28
2、安装selenium-webdriver的包
npm i selenium-webdriver
3、自动化采集文本及图片
const download =require('download')const fs =require('fs')const path =require("path");const{ Builder, By, Key, until }=require('selenium-webdriver');functionchangeExtension(filename, newExtension){// 使用正则表达式找到文件名的扩展部分,并将其替换为新的扩展名return filename.replace(/\.[^/.]+$/,'.'+ newExtension);}(asyncfunctionstart(){let driver =awaitnewBuilder().forBrowser('chrome').build();await driver.get('https://www.juejin.cn/');await driver.findElement(By.css('.search-input')).sendKeys('前端', Key.ENTER);let elements =await driver.wait(until.elementsLocated(By.className('content-box')),10000);const infos =await Promise.all(elements.map(asyncitem=>{const userName =await item.findElement(By.css('.meta-list .user-popover')).getText()const time =await item.findElement(By.css('.meta-list li:nth-child(2)')).getText()const type =await item.findElement(By.css('.meta-list li:nth-child(3)')).getText()const title =await item.findElement(By.css('.title')).getText()let img ='';const imgDom =await item.findElements(By.css('.thumb'));if(imgDom.length >0){const src =await imgDom[0].getAttribute('src')||'';if(src){
img =changeExtension(src,'png');}}return{userName: userName,time: time,type: type,title: title,img: img
};}));let jsonData =JSON.stringify(infos,null,2);const distDir = path.join(__dirname,"dist");if(!fs.existsSync(distDir)){
fs.mkdirSync(distDir);}
fs.writeFile("dist/data.json", jsonData,(err)=>{if(err)throw err;});
Promise.all(infos.map(info=>{if(info.img){download(info.img).then(data=>{
fs.writeFileSync(`dist/${info.userName}.png`,data)})}})).then(()=>{
console.log('files downloaded!');});
console.log('info9', infos)})();
4、滚动加载更多数据并采集
const download =require('download');const fs =require('fs');const path =require("path");const{ Builder, By, Key, until }=require('selenium-webdriver');functionchangeExtension(filename, newExtension){// 使用正则表达式找到文件名的扩展部分,并将其替换为新的扩展名return filename.replace(/\.[^/.]+$/,'.'+ newExtension);}(asyncfunctionstart(){let driver =awaitnewBuilder().forBrowser('chrome').build();await driver.get('https://www.juejin.cn/');await driver.findElement(By.css('.search-input')).sendKeys('前端', Key.ENTER);constcollectData=async()=>{let elements =await driver.wait(until.elementsLocated(By.className('content-box')),10000);const infos =await Promise.all(elements.map(asyncitem=>{const userName =await item.findElement(By.css('.meta-list .user-popover')).getText();const time =await item.findElement(By.css('.meta-list li:nth-child(2)')).getText();const type =await item.findElement(By.css('.meta-list li:nth-child(3)')).getText();const title =await item.findElement(By.css('.title')).getText();let img ='';const imgDom =await item.findElements(By.css('.thumb'));if(imgDom.length >0){const src =await imgDom[0].getAttribute('src')||'';if(src){
img =changeExtension(src,'png');}}return{userName: userName,time: time,type: type,title: title,img: img
};}));return infos;};let allInfos =[];const maxScrolls =6;// 最大滚动次数let scrolls =0;let lastInfosLength =0;while(scrolls < maxScrolls){let infos =awaitcollectData();
allInfos = allInfos.concat(infos);// 滚动到页面底部await driver.executeScript('window.scrollTo(0, document.body.scrollHeight)');await driver.sleep(2000);// 等待页面加载// 检查是否有更多内容加载,如果没有则退出循环if(infos.length === lastInfosLength)break;
lastInfosLength = infos.length;
scrolls++;}let jsonData =JSON.stringify(allInfos,null,2);const distDir = path.join(__dirname,"dist");if(!fs.existsSync(distDir)){
fs.mkdirSync(distDir);}
fs.writeFile("dist/data.json", jsonData,(err)=>{if(err)throw err;});
Promise.all(allInfos.map(info=>{if(info.img){download(info.img).then(data=>{
fs.writeFileSync(`dist/${info.userName}.png`,data)})}})).then(()=>{
console.log('files downloaded!');});
console.log('info', allInfos);})();
3、selenium常用api的列举
API说明示例
driver.get(url)
打开指定的 URL
await driver.get("https://www.example.com");
driver.findElement(By)
查找并返回匹配的单个 Web 元素
let element = await driver.findElement(By.id("element_id"));
driver.findElements(By)
查找并返回匹配的所有 Web 元素,返回一个列表
let elements = await driver.findElements(By.className("element_class"));
driver.wait(condition, timeout)
等待某个条件成立,最多等待指定的时间
let element = await driver.wait(until.elementLocated(By.id("element_id")), 10000);
driver.executeScript(script, *args)
执行 JavaScript 脚本
let title = await driver.executeScript("return document.title;");
driver.sleep(seconds)
使当前线程休眠指定的秒数
await driver.sleep(5000);
driver.getTitle()
获取当前页面的标题
let title = await driver.getTitle();
driver.getCurrentUrl()
获取当前页面的 URL
let currentUrl = await driver.getCurrentUrl();
driver.close()
关闭当前窗口
await driver.close();
driver.quit()
关闭所有窗口并退出 WebDriver 会话
await driver.quit();
element.click()
点击元素
await element.click();
element.sendKeys(keys)
向元素发送键盘输入
await element.sendKeys("text to input");
element.clear()
清除元素中的内容
await element.clear();
element.getText()
获取元素的文本内容
let text = await element.getText();
element.isDisplayed()
检查元素是否显示
let isDisplayed = await element.isDisplayed();
element.isEnabled()
检查元素是否可用
let isEnabled = await element.isEnabled();
element.isSelected()
检查元素是否被选中
let isSelected = await element.isSelected();
driver.switchTo.frame(frame_reference)
切换到指定的 iframe
await driver.switchTo().frame("frame_name");
driver.switchTo.defaultContent()
切换回主文档
await driver.switchTo().defaultContent();
4、Puppeteer的使用
1、puppereer的安装
npm i puppeteer
# or "yarn add puppeteer"
当你安装 Puppeteer 时,它会下载最新版本的Chromium(170MB Mac,282MB Linux,~280MB Win),以保证可以使用 API。
2、puppeteer截图
const puppeteer =require('puppeteer');(async()=>{const browser =await puppeteer.launch();const page =await browser.newPage();await page.setViewport({width:1920,height:2000});//waitUntil: 'networkidle2' 会等待页面的网络连接在500毫秒内没有超过2个请求时,认为页面加载完成await page.goto('https://www.4399.com/',{waitUntil:'networkidle2'});await page.screenshot({path:'4399.png'});await browser.close();})();
3、自动化滚动并采集
const puppeteer =require('puppeteer');const fs =require('fs');const path =require('path');const download =require('download');(async()=>{const browser =await puppeteer.launch({headless:true});const page =await browser.newPage();await page.goto('https://www.juejin.cn/');// 输入搜索关键字并提交await page.type('.search-input','后端');await page.keyboard.press('Enter');await page.waitForSelector('.content-box',{timeout:10000});// 滚动并采集数据const infos =[];let previousHeight;let scrollCount =0;const maxScrolls =15;// 最大滚动次数while(scrollCount < maxScrolls){const newInfos =await page.evaluate(()=>{functionchangeExtension(filename, newExtension){return filename.replace(/\.[^/.]+$/,'.'+ newExtension);}const items = document.querySelectorAll('.content-box');return Array.from(items).map(item=>{const userName = item.querySelector('.meta-list .user-popover')?.innerText ||'';const time = item.querySelector('.meta-list li:nth-child(2)')?.innerText ||'';const type = item.querySelector('.meta-list li:nth-child(3)')?.innerText ||'';const title = item.querySelector('.title')?.innerText ||'';let img ='';const imgDom = item.querySelector('.thumb');if(imgDom){const src = imgDom.getAttribute('src');if(src){
img =changeExtension(src,'png');}}return{ userName, time, type, title, img };});});
infos.push(...newInfos);
previousHeight =await page.evaluate('document.body.scrollHeight');await page.evaluate('window.scrollTo(0, document.body.scrollHeight)');awaitnewPromise(resolve=>setTimeout(resolve,2000));// 等待加载新的内容const newHeight =await page.evaluate('document.body.scrollHeight');if(newHeight === previousHeight){break;}
scrollCount++;
console.log(`开始采集${scrollCount}页数据`)}// 去重处理const uniqueInfos = Array.from(newSet(infos.map(a=>JSON.stringify(a)))).map(b=>JSON.parse(b));const jsonData =JSON.stringify(uniqueInfos,null,2);const distDir = path.join(__dirname,"dist");if(!fs.existsSync(distDir)){
fs.mkdirSync(distDir);}
fs.writeFileSync(path.join(distDir,"data.json"), jsonData);await Promise.all(uniqueInfos.map(async(info)=>{if(info.img){const data =awaitdownload(info.img);
fs.writeFileSync(path.join(distDir,`${info.userName}.png`), data);}}));
console.log('采集完成');
console.log('info:', uniqueInfos);await browser.close();})();
Puppeteer是一个由Google开发的无头浏览器库,可以在后台执行浏览器操作,不会弹出可见的浏览器窗口,因此可以更高效地进行网页自动化和爬虫操作。也可以通过设置headless 为false,来打开浏览器查看采集过程:await puppeteer.launch({ headless: false});
5、puppeteer常用api的列举
API说明示例
puppeteer.launch(options)
启动一个新的浏览器实例
const browser = await puppeteer.launch({ headless: true });
browser.newPage()
创建一个新的页面
const page = await browser.newPage();
page.goto(url)
导航到指定的 URL
await page.goto('https://www.example.com');
page.waitForSelector(selector)
等待指定的选择器出现在页面中
await page.waitForSelector('#element_id');
page.$(selector)
查找并返回匹配的单个元素
const element = await page.$('#element_id');
page.$$(selector)
查找并返回匹配的所有元素,返回一个数组
const elements = await page.$$('.element_class');
page.evaluate(pageFunction, ...args)
在页面上下文中执行 JavaScript 代码
const title = await page.evaluate(() => document.title);
page.click(selector)
点击指定的元素
await page.click('#element_id');
page.type(selector, text)
在指定的元素中输入文本
await page.type('#input_id', 'text to input');
page.screenshot(options)
截取页面截图
await page.screenshot({ path: 'screenshot.png' });
page.pdf(options)
将页面保存为 PDF
await page.pdf({ path: 'page.pdf', format: 'A4' });
page.setViewport(viewport)
设置页面视口大小
await page.setViewport({ width: 1280, height: 800 });
page.content()
获取页面的 HTML 内容
const content = await page.content();
page.title()
获取页面的标题
const title = await page.title();
page.url()
获取页面的 URL
const url = await page.url();
page.waitForTimeout(milliseconds)
等待指定的时间
await page.waitForTimeout(5000);
page.waitForNavigation(options)
等待页面导航
await page.waitForNavigation();
page.waitForFunction(pageFunction, options, ...args)
等待指定的函数返回 true
await page.waitForFunction(() => document.querySelector('#element_id') !== null);
elementHandle.click()
点击元素
await element.click();
elementHandle.type(text)
在元素中输入文本
await element.type('text to input');
elementHandle.evaluate(pageFunction, ...args)
在元素上下文中执行 JavaScript 代码
const text = await element.evaluate(el => el.textContent);
browser.close()
关闭浏览器实例
await browser.close();
5、技术文档
selenium中文文档: https://www.selenium.dev/zh-cn/documentation/webdriver/getting_started/using_selenium/
puppeteet中文文档:https://puppeteer.bootcss.com/
四、爬虫的危害
虽然爬虫在数据收集和分析方面有许多合法和有益的应用,但不当使用爬虫也会带来一系列的危害。
- 服务器负载增加:- 大量的爬虫请求会对目标网站的服务器造成过大的负载,可能导致服务器性能下降,甚至崩溃。这不仅影响网站的正常运营,还可能导致用户体验变差。
- 数据隐私和安全问题:- 爬虫可能会获取到敏感信息或个人数据,导致数据泄露和隐私问题。这种行为可能违反数据保护法律和法规,给网站所有者和用户带来法律风险。
- 知识产权侵权:- 爬虫可能会未经授权地复制和使用网站上的内容,侵犯版权和其他知识产权。这种行为可能导致法律纠纷和经济损失。等。。。
为了避免上述危害,使用爬虫时应遵循以下原则:
- 遵守网站的robots.txt文件和使用条款。
- 避免频繁访问,设置合理的访问间隔。
- 不获取和使用敏感信息或个人数据。
- 遵守相关法律法规,尊重知识产权。
通过合理和合法地使用爬虫技术,可以有效地获取所需数据,同时避免对目标网站和其他相关方造成不良影响。
版权归原作者 Moyo203 所有, 如有侵权,请联系我们删除。