百度百科介绍:css
Selenium [1] 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操做同样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否可以很好得工做在不一样浏览器和操做系统之上。测试系统功能——建立回归测试检验软件功能和用户需求。支持自动录制动做和自动生成 .Net、Java、Perl等不一样语言的测试脚本。html
Browser | Component |
---|---|
Chrome | chromedriver(.exe) |
Internet Explorer | IEDriverServer.exe |
Edge | MicrosoftWebDriver.msi |
Firefox | geckodriver(.exe) |
Safari | safaridriver |
根据本身的环境进行下载,将下载好的压缩包解压到项目的根目录不须要安装,各个浏览器的版本和dirver的版本的选择须要相近,不能盲目选择最新的版本,不然会出现意想不到的bug,建议最好将浏览器升级至最新的稳定版本并选择对应的包。前端
npm install selenium-webdriver
// 1. 引入selenium-webdriver包,解构须要的对象和方法 const {Builder, By, Key, until} = require('selenium-webdriver'); // 2. 将须要的代码包在一个自执行函数中 (async function example() { // 实例化 driver 对象, chrome 表明使用的浏览器 let driver = await new Builder().forBrowser('chrome').build(); try { // 须要打开的网站地址 await driver.get('https://www.baidu.com/'); // Key.RETURN enter回车 // By.id('id') 百度查询滴输入内容 // 找到元素 向里面发送一个关键字并按回撤 await driver.findElement(By.id('kw')).sendKeys('酒店', Key.RETURN); // 等1秒以后,验证是否搜索成功 // await driver.wait(until.titleIs('酒店_百度搜索'), 1000); } finally { // 关闭浏览器 // await driver.quit(); } })();
一句话搞定自动打开掘金首页git
// 自动打开掘金 await driver.get('https://juejin.im/timeline');
在浏览器中,查看页面的布局结构,找到小册的位置,如果使用jq进行dom选择,则是 $('.main-header-box .nav-item:nth-of-type(4)')
github
selenium中的By拥有不少的选择,其使用规则和jq很是类似,By.css('.main-header-box .nav-item:nth-of-type(4)')即可以找到对应的元素,调用click事件就能够模拟自动点击web
// 点击小册子的navBar 切换路由到小册 await driver .findElement(By.css('.main-header-box .nav-item:nth-of-type(4)')) .click(); await driver.sleep(1000)
while (true) { let listViewError = true; try { // 获取小册列表 let _li = await driver.findElements(By.css('.list-wrap .books-list .item')); console.log(_li.length); for (let i = 0, _len = _li.length; i < _len; i++) { const itemInfo = _li[i]; const title = await itemInfo.findElement(By.css('.info .title')).getText() const desc = await itemInfo.findElement(By.css('.info .desc')).getText() let price = await itemInfo.findElement(By.css('.info .price-text')).getText() _result.push({ title, desc, price }) } console.log('_result',_result); } catch (error) { if (error) listViewError = false; } finally { if (listViewError) break; } }
在获取列表的时候,为何会在最外层增长一个while呢?在 try catch 中的处理又是起到什么做用?chrome
- while能确保会不断的获取数据,直到页面渲染完成获取到指望的数据
- try catch 能够保证程序在遇到异常时不会直接终止程序,能够继续运行
- listViewError表示程序是否存在异常状况,如果存在则会进入 catch 中,这个时候 listViewError 为 false,finally 则不会走break,会继续执行while程序,直到能获取到数据finally才为true,这个时候 finally中则会break 整个while的循环,跳出循环继续执行
几十行的代码即可以将掘金的小册数据所有爬到,仍是简单和好用的npm
所有代码api
/* * @Author: nordon-wang * @Date: 2019-08-13 11:05:36 * @Description: 爬取掘金数据 */ const { Builder, By, Key, until } = require('selenium-webdriver'); let _result = []; // 用来收集获取的数据 (async function start() { let driver = await new Builder().forBrowser('chrome').build(); try { // 自动打开掘金 await driver.get('https://juejin.im/timeline'); // 点击小册子的navBar 切换路由到小册 await driver .findElement(By.css('.main-header-box .nav-item:nth-of-type(4)')) .click(); await driver.sleep(1000) // 点击二级菜单 await clickViewNav(driver); await driver.sleep(1000) // 获取数据 await getList(driver); } catch (error) { console.log(error); } finally { let timer = setTimeout(async () => { clearTimeout(timer); await driver.quit(); }, 600000); } })(); // 获取渲染完成的按钮 async function clickViewNav(driver) { while (true) { let viewNavError = true; try { await driver .findElement(By.css('.main-container .view-nav .nav-item:nth-of-type(2)')) .click(); } catch (error) { if (error) viewNavError = false; } finally { if (viewNavError) break; } } } // 获取列表数据 // 页面在渲染完成以前没法获取到页面的元素 async function getList(driver) { while (true) { let listViewError = true; try { // 获取小册列表 let _li = await driver.findElements(By.css('.list-wrap .books-list .item')); console.log(_li.length); for (let i = 0, _len = _li.length; i < _len; i++) { const itemInfo = _li[i]; const title = await itemInfo.findElement(By.css('.info .title')).getText() const desc = await itemInfo.findElement(By.css('.info .desc')).getText() let price = await itemInfo.findElement(By.css('.info .price-text')).getText() _result.push({ title, desc, price }) } console.log('_result',_result); } catch (error) { if (error) listViewError = false; } finally { if (listViewError) break; } } }