有些时候你想在你的应用需要用到一些背景图片,但是没有图片啊,没有图片啊,没有图片啊。。。。。
当然你可以在应用内内置很多的精美图片,然后就造成了一些问题:你的apk变得贼大,其次想换一些新的图片只能在下一次应用更新。
或者搞一个服务器,用网络请求去访问服务器的图片,那么问题来了:谁去搞服务器,服务器的图片哪里来的。相信很多android端盆友对搭建服务器还是比较陌生的(比如我)。
于是我想了个可以投机取巧的办法,用别人家的图片,对,没有错,虽然这种方式有点不要脸,但是我只能这么干了。。。
主体思路如下:
应用http访问网页,获取网页界面,然后用正则将详情图匹配出来,获取到所有图片的url。。。
不多说了,开干吧。
找一个目标网页
首先要确定想要从什么网站上面爬取图片数据,我在github中的一个项目里是爬取的google图片搜索网站的图片数据,这里我从爬取pixabay的图片吧,链接:https://pixabay.com/
了解目标网页的url结构以及参数功能
有的盆友可能说了我没做过前端啊,,,我知道我也没做过,但是没吃过猪肉还没么见过猪跑吗,一点一点摸出来就可以了
比如我在pixabay搜索动物anim,结果如下:
他是通过path的方式去访问的,行,了解,先写一个http请求去访问这个界面,看看拿到的是什么东西,因为本人比较懒,所以直接用okhttp去写网络请求了;
public class PixabayUtils {public static void search() {OkHttpClient client = new OkHttpClient.Builder().build();final Request request = new Request.Builder().header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36").url("https://pixabay.com/images/search/anim/").build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.e("GFZY", "onFailure: " + e.getMessage());}@Overridepublic void onResponse(Call call, Response response) throws IOException {
// Log.i("GFZY", "onResponse: " + response.body().string());Log.i("GFZY", "onResponse: ");FileOutputStream fileOutputStream = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "AAAG.html"));fileOutputStream.write(response.body().string().getBytes());fileOutputStream.close();}});}
}
这里简单说一下为什么要添加User-Agent,原因有两个:在进行网络请求时,有些‘错误’的请求头会被网站当做爬虫(也就是咱们),所以为了模仿一个正常的网页打开,我们要设置一个user-agent,俗称反爬。其次,有些用过okhttp的同学可能接触过okhttp会将你的user-agent替换为okhttp-xxx,这样你拿到的数据就会有问题,当时在访问google图片的时候就是因为没有设置user-agent,所以拿到的结果没有详情图的url。
至于这个user-agent从哪里拿,网上有很多android获取默认user-agent的博客,大家自己找一下吧,再或者你可以打开你的网站的开发者模式,点开network,锁边找到一个网路请求,然后找到他的请求头,直接复制过来?
至于将网页结果存到手机,是为了验证拿到的结果是不是正确的,不必太在意。
行,这个事情就到这里,我们接着走。
简单跑一下(如果你说程序跑的时候有什么问题,先检查一下读写权限和网络权限),然后把结果html用电脑打开:
是正常的。看来现在为止没什么问题,看到图片地址了,是不是很高兴!
别高兴太早了,这只是一个缩略图,分辨率低的可怜,除非你的显示区域很小,要是想弄全屏的,你可以看下效果,马赛克亮瞎你的眼。
找详情图url
网页上放置的大多数都是缩略图,而不同的网站详情图url放置的位置不一样,想google会把详情图url放在网页底部,等待动态调用,而大多数跳转式的网页应该会附带详情图的url,再点击后二次请求(个人猜测,)所以说这个工作还是要往出试。
这样的话那先点击一下进入详情页看看url的变化:
在我点击详情页之后path从anim变成了这个东西,如果说网页内可以找到这段path,那就什么都好说了,来我们看一下预览界面有没有这个字段哈哈:
果真如此,也就是说预览网址在href字段中会保留详情页的跳转界面 (只是针对pixabay,其他网站还需要自己往出推)
我们看看详情页中详情图的url存放在哪里:
好了,我们总结一下:对于这种跳转式的网站,想要获取他的详情图,需要进行如下的几个步骤:
- 观察url参数,知道关键的字段功能
- 在预览网页中找到详情页的url
- 在详情页中找到详情图的图片url
- 在一次访问获取所有详情页url后,遍历访问所有详情页url,抓取详情图的url
正则匹配url
可能抓取url的方式有很多,个人感觉正则是比较方便的一个方法。
首先获取预览网页中所有详情页的url:
@Overridepublic void onResponse(Call call, Response response) throws IOException {
// Log.i("GFZY", "onResponse: " + response.body().string());Log.i("GFZY", "onResponse: ");
// FileOutputStream fileOutputStream = new FileOutputStream(new File(Environment.getExternalStorageDirectory()
// , "AAAG.html"));
// fileOutputStream.write(response.body().string().getBytes());
//
// fileOutputStream.close();String resStr = response.body().string();Pattern pattern = Pattern.compile("(?<=href=\").*?(?=\")");Matcher matcher = pattern.matcher(resStr);ArrayList<String> detailsUrlList = new ArrayList<>();while (matcher.find()) {String group = matcher.group();//根据目标特征限制条件,否则匹配的情况太多了if (group.startsWith("/photos")&& group.charAt(group.length() - 1) >= '0'&& group.charAt(group.length() - 1) <= '9') {detailsUrlList.add("https://pixabay.com" + group);}}for (String s : detailsUrlList) {Log.i("GFZY", "onResponse: " + s);}}
结果如下:
遍历list,二次访问
for (String s : detailsUrlList) {
// Log.i("GFZY", "onResponse: " + s);Request detailRequest = new Request.Builder().url(s).get().header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36").url("https://pixabay.com/images/search/anim/").build();client.newCall(detailRequest).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.e("GFZY", "onFailure: " + e.getMessage());}@Overridepublic void onResponse(Call call, Response response) throws IOException {String resStr = response.body().string();
// Log.i("GFZY", "onResponse: " + resStr);Pattern detailPattern = Pattern.compile("(?<=srcset=\").*?(?=\")");Matcher detailMatcher = detailPattern.matcher(resStr);while (detailMatcher.find()) {Log.i("GFZY", "onResponse: " + detailMatcher.group());}}});}
结果如下:
这个就是我们最后想要拿到的数据了,至于这两个网页怎么处理,大家可以自己弄了。
拿到详情图的url后,是想自己下载还是加载显示出来看大家需求了,这个功能到这里就完成了,怎么样,高兴不
之前我是搜索的Google图片网站,已经把功能封装成依赖,大家是在不想看上面这一坨坨的话可以远程直接调用,github链接如下:
https://github.com/gfzy9876/GoogleImgSearch