本文分享一个基于 Java HttpClient 4.5 的知乎爬虫实战案例,实现了 90 万+ 活跃用户基础信息的自动化采集,涵盖模拟登录、多线程架构、去重策略等核心技术点。
采用「生产者-消费者」双线程池模型:
public boolean login(CloseableHttpClient client, HttpClientContext context) {
// 1. 获取登录页 _xsrf token
HttpGet get = new HttpGet("https://www.zhihu.com/#signin");
HttpClientUtil.getWebPage(client, context, get, "utf-8", false);
// 2. 处理验证码(人工识别)
String captcha = downloadAndRecognizeCaptcha(client, context);
// 3. 提交登录表单
HttpPost post = new HttpPost("https://www.zhihu.com/login/email");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("captcha", captcha));
params.add(new BasicNameValuePair("email", "你的邮箱"));
params.add(new BasicNameValuePair("password", "你的密码"));
params.add(new BasicNameValuePair("remember_me", "true"));
post.setEntity(new UrlEncodedFormEntity(params, "utf-8"));
String result = HttpClientUtil.getWebPage(client, context, post, "utf-8", false);
JSONObject json = new JSONObject(result);
if ("0".equals(json.getString("r"))) {
// 登录成功,序列化 Cookie 到磁盘
HttpClientUtil.serializeObject(context.getCookieStore(), "zhihu_cookies");
return true;
}
return false;
}
使用 MD5 哈希处理 URL 后存入数据库,每次抓取前查询是否存在:
String urlMd5 = DigestUtils.md5Hex(url); if (db.exists(urlMd5)) return; // 已抓取 db.save(urlMd5); // 标记为已抓取
// 解析线程逻辑
while (running) {
String html = storage.take(); // 从队列获取 HTML
User user = parseUserProfile(html); // 解析用户信息
userDao.save(user); // 入库
List<String> followUrls = parseFollowUrls(html); // 提取关注列表
for (String url : followUrls) {
if (!db.exists(DigestUtils.md5Hex(url))) {
fetchPool.submit(() -> fetchPage(url)); // 提交给抓取线程池
}
}
}