爬虫介绍
- 通过模拟浏览器的请求,服务器就会根据我们的请求返回我们想要的数据,将数据解析出来,并且进行保存
node文件执行命令: node . 文件名
爬虫流程
目标:确认想要获取的数据
- 1.确定想要的数据在什么页面上(一般详细的数据会在详情页)
- 2.确定在那些页面可以链接到这些页面(一般分类列表页面会有详情页的链接数据)
- 3.寻找页面之间和数据之间的规律
分析页面
- 1.获取数据的方式(正则,cherrio)
- 2.分析数据是通过ajax请求的数据,还是html里自带的数据
- 3.如果是通过AJAX请求的数据,那么需要获取ajax请求的链接,一般请求到的数据都为JSON格式数据,那么就会比较容易解析
- 4.如过数据在HTML里面,那么就用cherrio通过选择器将内容选中
编写单个数据获取的案例
- 1.解析出分类页的链接地址
- 2.解析出列表页的链接地址
- 3.解析出详情页的链接地址
- 4.解析详情页里面想要获取的数据
- 5.将数据进行保存到本地或者数据库
如果遇到阻碍进行反爬虫对抗
- 1.User-Agent是否为正常浏览器的信息(如果时axios者只为header)
- 2.将请求头设置为跟浏览器一样的内容
- 3.因为爬虫的爬取速度过快,会导致封号。(1.降低速度解决 2. 使用代理解决)
- 4.如果设置需要凭证,那么可以采用无界浏览器真实模拟
请求的数据的库
- request:通过库,帮助我们快速实现HTTP请求包的打包
1
2
3request.get('请求地址', {
'请求头字段':'请求头的value值'
},(res)=> {处理返回的内容}) - axios:通过库,帮助我们快速实现HTTP请求包的打包,比request更好,前后端通杀,前后端调用方式一致
1
2
3
4
5
6
7
8axios({
method: 'get',
url: '请求地址',
resposeType: 'stream'
})
.then(function(response) {
response.data.pipe(fs.createWriteStream('写入的文件名'))
}) - puppeteer: 完全模拟浏览器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61// 打开浏览器
let options = {
defaultViewport: {
width: 1400,// 设置视窗宽高
height:800
},
headless: true,// 设置为无界面
slowMo: 250,// 调试时设置放慢每个步骤的毫秒数
timeout:3000, // 默认超时3秒钟
}
let browser = await puppeteer.launch(options)
// 打开新标签页
let page = await browser.newPage()
// 获取多有浏览器的页面
let pages = await browser.pages()
// 关闭浏览器
browser.close()
// 将页面跳转至
await page.goto(url)
// 获取页面的对象,并进行操作
let btn = await page.$(selector)
let input = await.page.$(selector)
// 点击按钮
btn.click()
// 聚焦到输入框
input.focus()
// 在页面上写入内容或者键盘按键
await page.keyboard.type('content')
await page.keyboard.press('content')
await page.keyboard.tdown('content')
// 设置鼠标的移动
await page.mouse.move(0,0)
await page.mouse.down()
await page.mouse.move(0,100)
await page.mouse.move(100,0)
await page.mouse.move(100,1000)
await page.mouse.up()
// 截获页面请求
await page.setRequestInterception(true)
// 监听请求事件并对请求进行拦截
page.on('request',request => {
// 通过url模块对请求的地址进行解析
request.url() // 可以获取请求的网址,request包含了所有的请求信息
if(想要的条件){
request.continue()
}else {
request.abort([errorCode])
}
})
// 获取浏览器的信息和内容
page.$eval(selector,(item)=> item)
page.$$eval(selector,(item)=> item)
反爬虫策略:
几秒钟请求的次数达到一定程度,就会发送验证码、返回其它数据等方式来检验是否有问题
解决方式:使用代理proxy1
2
3
4
5
6
7
8proxy: {
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},代理获取途径:花钱,或者找免费代理,但需要一个个ping ip是否响应
免费代理IP:117.69.201.242 端口:9999
免费代理IP:125.73.220.108 端口:9999
免费代理IP:113.124.85.162 端口:9999
免费代理IP:114.230.69.33 端口:9999获取到的字体图标的数据是乱码的,需要下载它的字体图标并解码,花费时间和精力多,需要考虑清除是否一定要去解码
网页不能直接获取源代码,这种叫前端渲染网页,无法爬取。
- 示例:易点租网页。后端渲染的网页可以爬取
- 需要分析请求的接口对应哪些内容是
let res = await axios.get(httpUrl, {proxy: {
host: ‘127.0.0.1’, // 找的代理和端口
port: 9000,
},
})
Puppeteer — 无界面模式
- 不用打开Chrome界面就可以操作Chrome界面
- 作用:可以通过api直接控制Cheome模拟大部分用户操作来进行UI Test或者作为爬虫访问页面来收集数据
- 生成页面PDF
- 抓取SPA并生成预渲染内容(SSR)
- 自动提交表单,进行UI测试,键盘输入
- 解决了网页为前端渲染,无法直接爬取的问题。直接将页面直接渲染到源码
- 使用方式:
- 使用Chrome打开这个网页打开F12就可以看到详细的网页源代码
- 然后直接在控制台中输入document.querySelector(“选择器”).getAttribute(“src”)就可以直接获取对应信息
- 图像识别
截屏
- await page.screenshot({path: ‘example.png’}); // 打开页面的时候截屏,path为截屏的图片名字
跳转到新页面的方式
- 方式一:获取对应信息并自动打开对应链接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 获取页面内容
// $$eval函数使得回调函数可以运行在浏览器中,并可以通过浏览器的方式进行输出
let eles = await page.$$eval("#menu li a", (elements)=> {
let eleArr = []
elements.forEach((item,i) => {
var eleObj = {
href: item.getAttribute("herf"),
text: item.innerText
}
eleArr.push(eleObj)
})
return eleArr
})
// 自动打开国内电影的页面
let gnPage = await browser.newPage
await gnPage.goto(eles[2].href) - 方式二:点击跳转
1
2
3// 通过点击页面跳转的方式
elementHandles = await page.$$("menu li a")
elementHandles[2].click() - 方式三:自动打开搜索内容的页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 通过表单输入进行搜索(看文档是否为promise对象,是+await)
inputEle = await page.$(".searchl .formhue")
// 让光标进入到输入框
await inputEle.focus()
// 往输入框输入内容
await page.keyboard.type("热烈")
// 绑定事件,取消冒泡 --- 因为点击按钮,自动冒泡打开了广告
await page.$eval('.bd3rl> .searchr', (element) => {
element.addEventListener('click', (e) => {
e.cancelBubble = true
})
})
// 点击按钮(找到按钮的选择器)
let btnEle = await page.$('.searchr input[name="Submit"]')
await btnEle.click()