Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

爬虫经验分享 #20

Open
shen1992 opened this issue Dec 11, 2019 · 0 comments
Open

爬虫经验分享 #20

shen1992 opened this issue Dec 11, 2019 · 0 comments

Comments

@shen1992
Copy link
Owner

shen1992 commented Dec 11, 2019

简介

  1. puppeteer抓取
  2. 分析接口
  3. 模板渲染抓取

puppeteer 抓取

灵感来源于downie软件

多个网站执行视频抓取逻辑,而这些逻辑基本相同,首先想到的就是puppeteer,puppeteer默认使用的浏览器是Chromium

Chromium和Chrome有什么区别?

Chrome是基于Chromium的,但谷歌在chrome浏览器中添加了Chromium所缺少的一些专有的、封闭源代码位。具体来说,Google采用了Chromium,然后添加了以下内容

  • AAC, H.264, 和MP3 支持:Chrome包含针对这些专有媒体格式的许可编解码器,可让您访问更多种媒体内容 - 尤其是使用HTML5视频传输H.264视频的网站。两种浏览器都包括基本的免费编解码器:Opus,Theora,Vorbis,VP8,VP9和WAV。
    ...

为了保证抓取效果,使用chrome代替Chromium

executablePath: '/usr/bin/google-chrome'

在服务器上下载chrome比较麻烦,因为国内的服务器无法访问境外的下载资源,由于我们还需要抓取youtobe的视频,所以搞了一台香港的云主机

puppeteer抓取信息的方式:

await page.evaluate(() => {
  return {
     document.getElementsByTagName('video')[0].currentSrc
  }
})

fs.createWriteStream(path, name)

遇到blob格式的视频,现在主流的视频网站基本都是这种格式,比如youtobe,b栈等

blob:https://www.youtube.com/d2708fb5-065a-4429-af77-9d67c96fa9c5

它特点是每隔一段时间去拉资源,根据用户的网络情况自动切换清晰度,但是对于我们来说抓取这种链接其实没有作用,因为无法将它转成视频,由于我了解到这种格式的视频对性能有要求,只在pc端支持,所以我想了一个骚操作使用手机模式打开,这样就可以获取一个mp4格式的资源了。

await page.emulate(iPhone)

一些网站也对视频抓取做了限制,比如快手做了个滑动验证

image

种cookie绕开快手网站的滑动验证

await page.setCookie(...)

puppeteer的优缺点

优点:

  • 适合做通用信息的抓取
  • 功能强大,还可以用来做自动化测试,性能分析等,爬虫只是一部分很小的应用

缺点:

  • 无论怎么优化,相对于其他方式的爬虫来说还是比较慢
  • 对于分页的数据比较无力

分析接口

举个抖音列表页的例子

分析返回值,找到里面视频的信息,找到分页的字段返回值有has_more证明有分页,然后看参数,怎么拼接链接,参数里面的max_cursor是上一页最后一个视频的id。

注意_signature的生成

先用puppeteer打开列表页,把请求的参数通过正则匹配都找出来,关闭浏览器

page.on('request', request => {
  if (request.resourceType() === 'xhr' && request.url().indexOf('/web/api/v2/aweme/post') > -1) {
    ....
  }
})

在代码中使用递归,发送请求,把每个视频的地址都找出来,抓取出来的网址需要经过一个302跳转,才能得到真正的视频资源地址

const urllib = require('urllib')

在python中urllib是一个自带的url请求库,node也有一个,底层是用node的http或https模块发起请求,封装了一些proxy等功能

抖音做了限制,请求头必须要有ua,才能正常返回,如果条件满足,会返回一个a标签,通过正则选取href属性的内容即为视频资源地址

分析接口的优点是速度快,缺点容易被封

一些防止被封的方式

  1. 分时函数:

每隔一段时间从数组中取出一组数据进行抓取,直到数组为空,时间间隔尽量随机,频率固定很容易就能判断是爬虫

  1. 挂代理,公司的代理有,本地使用需要挂的hy-vpn,上了服务器之后需要ping一下看看能不能ping通
const proxies = [
  'http://10.122.133.44:3128', 
  'http://10.172.113.149:3128', 
  'http://10.172.113.148:3128',
]

把他们放到数组里面,请求接口的时候随机从数组里面取出,这样每次请求接口的时候,ip地址可能都不一样

  1. 往请求头里面加ua和cookies,多找几个值,随机一下,尽量伪装是一个正常的用户

量级比较大的数据并发抓取

比如这种场景:要下载某个网站下的几万张图片。一个一个下载显然是不合适的,可以考虑并发抓取

const async = require('async')

async.mapLimit(urls, 5, async function(url) {
    const response = await fetch(url)
    return response.body
}, (err, results) => {
    if (err) throw err
    // results is now an array of the response bodies
    console.log(results)
})

每秒发起5个请求,等待所有请求完成之后继续,容易被封ip,请谨慎使用

有些网站的接口返回值做了加密处理,对于这种接口我们就无法抓取了

模板渲染抓取

举一个豆瓣的例子

const cheerio = require('cheerio')

抓取的信息可能需要写入到csv文件中

const Json2csvParser = require('json2csv').Parser
const iconv = require('iconv-lite')

const encode = iconv.encode(csv, 'utf-8')
fs.writeFile(name, encode)

增量式爬虫

每天开启一个定时器,观察某个分类的标签是否有更新,如果有,则进行抓取,抓取时与数据库的数据进行比对,只抓取新的并且存储

思考

能否结合1和3制作一个通用爬虫

下载视频

  1. 单个视频下载,直接访问服务上的资源地址
  2. 多个视频下载可以把他们打包成一个压缩文件,因为视频比较多,建立100多个下载任务浏览器会很卡
const archiver = require('archiver')

压缩成zip文件,mac和windows都能使用

防止重复打包的md5算法,应用范围比较广,截图工具也有使用

const crypto = require('crypto')
const md5 = crypto.createHash('md5')
let hash = md5.update(Buffer.from(videos)).digest('hex')

安全措施

image

没有解决的问题

服务器上的linux系统没有ui,登录方式无法做得更通用

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant