前言:
本人是在接触python爬虫后,萌发了“Android开发应该也能实现爬虫效果,这样用手机爬是不是会更方便”这一念想。于是兴趣使然就开始了手机爬虫的探索之旅。虽然这路已被探索无数次,但是对于未曾去过的我依旧向往。
一、整装待发:
1)爬虫工具和环境:
Android系统 Android studio2)入手前准备:
了解kotlin语言:由于Android studio 4.1使用的是kotlin语言,所以需要自行稍微了解一下其语言特性,如定义方式、逻辑表达式,当然你会发现kotlin语言还是比较友好的。 了解线程和多线程 了解爬虫流程 了解数据长久化二、地图浏览:
要实现如何手机爬虫,首先要知道爬虫的流程:
1)明确爬取目标
2)伪装访问
3)获取网页源码
4)提取出需要内容(常用手法:洗刷数据)
5)检验提取内容
6)爬取内容
7)爬取内容持久化
三、景点分析
<一>Jsoup使用
访问网页的手法有很多,如get、HttpClient 、HttpURLConnection等,但是我还是比较倾向于Jsoup。除了好用外,更多的是它和python的requests比较相似,所以用起来也比较顺手。
附上常用使用方法:
var d:Document = Jsoup.connect("这里填写网页地址")
.userAgent("用户代理").get()
userAgent:获取方法参考https://jingyan.baidu.com/article/95c9d20d7bca17ec4e7561a4.html
坑点:
(1)这个方法需要配合线程使用,不然会报错。
(2)当地址是下载文件的地址时,可能会报org.jsoup.UnsupportedMimeTypeException: Unhandled content type Must be text/* ,处理手法是加入ignoreContentType函数
Jsoup.connect(strvideoUrl)
.userAgent("用户代理")
.ignoreContentType(true).get()
<二>常用伪装访问:
1)Jsoup.connect(strvideoUrl).userAgent(…)
2)Jsoup.connect(strvideoUrl).referrer(…)
3)Jsoup.connect(strvideoUrl).cookie(…)
注:括号内的…表示参数,因为懒所以就用…表示。用法类比python的request
<三>提取出需要内容:
利用Document类对象存储的内容进行提取。如何提取,可参考jsoup是如何选择指定元素的
个人极不推荐使用正则来洗刷数据,因为在Android里,正则的匹配率实在是低得感人,不好用。
推荐的手法是,先用Document的select和Elements的getElementsByAttribute函数进行筛选,在Document.select和Elements.getElementsByAttribute无法一步到位精准筛选到目标时,再考虑用Elements.attr()函数进行进一步筛选。
elementUrl.first().getElementsByAttribute("src")//利用属性的名称来定位
筛选数据常用到的:
1)Document.select
2)Elements.getElementsByAttribute
3)Elements.attr
4)Elements.removeAttr
5)Elements.replace
var elementTitle: Elements =d.select("[class*=\"video-title title-truncate m-t-5\"]")
//d为Document对象,获取方法如:var d:Document=Jsoup.connect("http://www.baidu.com/").get()
注:需要进行字符分割时,可以用String自带的split函数进行操作,比较便捷。
d.text().toString().split("#EXT-X-DISCONTINUITY")
<四>数据持久化
所谓的数据持久化,无非就是把数据保存下来,这一步无论在Python爬虫还是今天讲的Android爬虫,都是属于核心部分。下载手法有以下几种:
1. 自己封装URLConnection 连接请求类
2. Android自定的下载管理
3. 使用第三方 okhttp 网络请求框架
具体说明参考:Android 文件下载三种基本方式
其实这三种方式,我都试过,最后因为便捷,所以选择了第二个下载方案:Android自定的下载管理。因为这个下载方案是调用了现有的下载框架进行下载,减轻了许多代码量。
优点: 会在notification 显示下载的进度,同时可以暂停、重新连接。
使用手法:
//创建下载任务,downloadUrl就是下载链接
val request = DownloadManager.Request(Uri.parse(strvideodownloadUrl[i]))
//指定下载路径和下载文件名
request.setDestinationInExternalPublicDir("", "/storage/"+strTitle+'/')
//获取下载管理器
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
//将下载任务加入下载队列,否则不会进行下载
downloadManager.enqueue(request)
println(i.toString()+".ts"+"已完成"+'\n')
与Python对比:
在Python中下载一般都是使用多线程调用函数下载,但是 “自定的下载管理” 这种下载方案使Android爬虫的下载方式具有一定的先天优势。
Okey,到这里其实整个Android爬虫就讲完了,是不是觉得很简单呢。摸索的过程比较曲折,但是也比较有趣。最后给出本文的另一核心重点–视频合并。
<五>视频合并
网上爬下来的视频文件一般都是ts文件居多,当然Android是能播放ts文件的,但是一百或几百个ts,一个个播放这也是需要相当的耐心,那合并成一个mp4文件是不是众望所归?Python可以通过调用”copy /b“指令进行ts文件合并,那Android是如何把多个ts文件合并成一个文件呢?
想必很多人在网上搜索过,但是多数搜索到的是使用软件进行合并,但是作为一个开发爱好者,还是想自己的软件能自实现合并。
val fos = FileOutputStream(realFile) //fos承载的是输出文件
var file:File =File("/storage/emulated/0/storage/"+strTitle+'/'+"video"+strnum+".ts")
if (file.exists()){
var fis=FileInputStream(file)
var tmpBytes = ByteArray(fis.available())
var length = tmpBytes.size
println(length)
if(i==0){
while(fis.read(tmpBytes)!=-1){
fos.write(tmpBytes,0,length)
}
}
//之后的文件,去掉头文件就可以了.amr格式的文件的头信息为 6字节
//当然去不去这6字节都是能合并的,合并出来的文件也能正常播放
else{
while(fis.read(tmpBytes)!=-1){
fos.write(tmpBytes,6,length-6)
}
}
fos.flush()
fis.close()
}
后感: 经过Android爬虫之旅后,感觉还是Python比较强大。
到此,全文已完结。文笔不好,将就看看。如果本文能让你学到东西,希望能点个赞。
成果展示:
点击”案例展示“按钮访问目标地址并开始下载
下载完成后,点击下方”等待下载完毕后点击下载“(打错字,改成合并囧)按钮,然后就会合并ts文件,并删除ts文件