前言
刷微博刷到一个博主求好看小姐姐照片的微博,内心不由得轻蔑一笑,好看的小姐姐凭啥理你,滑到评论区,我瞬间就酸了,内心对这个博主留下了嫉妒的泪水。
这样的照片评论区多的是,滑屏滑到手指酸痛还没有看完所有小姐姐的我灵机一动,不如写个爬虫把小姐姐照片全爬下来慢慢欣赏吧(吸溜~)!
页面分析
首先在chrom中打开开发者工具,打开微博链接,在network分析页面筛选XHR项,分析所有的请求
发现有一个hotflow的链接很有意思,查看了一下response,将json串在json解析工具中一看,果然就是我们要找的东西
顾名思义,user中是微博用户信息(有用户名,头像等信息),pic就是小改改们评论的图片,追求高清的我们当然要选择large中的图片啦!
正当我感觉一大波小姐姐在向我走来时,突然想到一个问题,微博评论的分页加载又该怎么处理?
下滑页面再次查看network控制台,发现请求的url中增加了一个max_id项,而这个参数正是第一次请求返回的json串中的max_id的值,至此,对于微博页面的这些分析已经可以让我们将小姐姐收入囊中了!
技术栈
- 语言:java
本来想用python来分析html页面操作的,但是发现使用一个http请求就可以完成,而自己手里又有现成的轮子,所以就用了自己比较熟悉的java - 数据库:redis
使用redis的原因主要是安装使用方便,用它来存储http请求获取到的max_id,实现断点续传,同时存储图片信息防止重复爬取 - 中间件:kafka
因为程序是部署在我自己的服务器上的,由于服务器存储比较小,所以服务器只将爬取到的信息处理后发送到kafka,我本地再起消费者来下载图片
架构
关键点
- 代理池
为防止同一ip访问微博过于频繁而被限制访问,增加了代理池,关键代码如下:
public static String sendPost(String url,String proxyHost,int proxyPort) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
Random random = new Random();
// 设置代理ip和端口信息
System.setProperty("https.proxyHost", proxyHost);
System.setProperty("https.proxyPort", proxyPort+"");
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
String useAgent = useAgentsList.get(random.nextInt(useAgentsList.size()));
System.out.println("本次请求使用agent"+useAgent);
conn.setRequestProperty("user-agent", useAgent);
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
// out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
免费代理ip获取地址: https://www.kuaidaili.com/free/
我直接复制了几个地址写死在程序中了,有需求可以自己去爬一下这个网站做代理池的定时更新
- 图片下载
代码如下:
public static int saveImg(String picUrl,String comId,String userName,int num) throws IOException{
// 保存图片
// new一个URL对象
URL url = null;
FileOutputStream outStream = null;
try {
url = new URL(picUrl);
// 打开链接
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
// 设置请求方式为"GET"
conn.setRequestMethod("GET");
// 超时响应时间为5秒
conn.setConnectTimeout(5 * 1000);
// 通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
// 得到图片的二进制数据,以二进制封装得到数据,具有通用性
byte[] data = readInputStream(inStream);
// new一个文件对象用来保存图片,默认保存当前工程根目录
String fileName = comId+";"+userName+ ".jpg";
File imageFile = new File(imgPath+fileName);
// 创建输出流
outStream = new FileOutputStream(imageFile);
// 写入数据
outStream.write(data);
// 关闭输出流
outStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
outStream.close();
++num;
return num;
}
}
剩下的就是kafka的生产消费者代码和json解析以及逻辑处理了,在这里就不多介绍了,大家可以按照自己的思路去处理。
成果
emmm,因为直接爬取的这条微博下的所有图片评论,所以好像混进了一些奇怪的东西,无伤大雅!不得不感叹,好看的小姐姐是真的好看,溜了溜了!
欢迎关注我的个人微信公众号,一个菜鸟程序猿的技术技术分享和奔溃日常