系列目录:
JAVA微博爬虫基础篇——简单的微博爬虫(手动cookie)
JAVA微博爬虫高级篇——自动获取微博cookie(无须账号、每日百万量级)
一、前言
文章这东西写起来是真的麻烦。我语文特不好,什么语句、语义不通之类的是常有的,请务必不要在意(你们在意也没用)。 我第一次用markdown写点东西,打算试试水,因此排版方面会比较乱。
语文不行,排版不行,写这些话的时候我自己都在想:“那你写这东西干嘛?直接放代码不是更方便?”。 人嘛,总是要试试的,不试过怎么知道你自己就是不行。
最后,本篇讲的是微博爬虫的基础实现,适用范围:小规模使用
二、原理
微博有一个“Sina Visitor System”(新浪访客系统),如果没有专门的微博cookie,所有请求都会被这个系统拦截。反过来说,只要获取到这个cookie,就能爬取到微博的页面。
类似的教程网上有很多,但实际上我感觉有很多教程一些细节(注意事项)都没有讲清楚,所以,我特意整理一下。
三、实现
爬虫我虽然推荐用python实现,不过在这里我用java给大家演示。因为不是每个人都会python的
其实是因为我以前已经用java实现过一遍,ctrl+cv就行,实在不想再写一遍。
接下来,就是实战。这次选用的是微博的榜单页面
1、cookie位置
获取cookie: 谷歌浏览器先登录微博。然后F12打开开发者模式,ctrl+R刷新请求,找到当前页面的请求,复制cookie。

2、maven依赖
本次选用的是请求工具是httpclient,解析页面是jsoup
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
3、java代码实现
- 微博的大部分页面的请求头其实只要设置"user_agent"和“host”还有“cookie” 就可以了,其余的可要可不要。
- 我对markdown不太熟悉,可能是代码因为太长导致代码显示实在太丑了,所以有些代码是截图的。
- 这些代码是18年写的,说真的有种看黑历史的感觉,完整类实在没脸给大家看,我就截点关键代码吧。
- 微博的页面数据是用FM.view()填充的,所以在解析页面的时候需要进行特殊处理
- 如有错漏,欢迎斧正。
第一步,创建实体类
先根据你要爬的字段,创建实体类
/**
* @ClassName: entity
* @Description: TODO(这里用一句话描述这个类的作用)
* @date 2018年2月23日 下午2:37:27
*/
@Data
public class WeiboDomain {
private String uid;
private String name;
private String url;
private String gender;
private String location;
private String description;
private String tag;
private String followers_count;
private Integer friends_count;
private Integer statuses_count;
private boolean isVip;
private String updateTime;
}
18年写的代码,突然有点怀念呢
第二步 创建get请求,获取页面数据
/**
* @Title: getHtml
* @Description: TODO(通过url返回页面数据)
* @param url
* @return
* String 返回类型
*/
public String getHtml(String url,String cookie) {
HttpGet httpGet = createHttpGet(url, cookie);
return get(httpGet);
}
createHttpGet方法设置请求头模拟真实用户。我们只要将上图的请求头信息复制进来,即可.

setProxy(httpHost)是用来设置代理的,没有需要的话可以不添加
private RequestConfig getRequestConfig() {
return RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000)
.setConnectionRequestTimeout(3000)
.setProxy(httpHost).build();
}
第三步 解析页面数据
通过上面的getHtml方法,我们可以得到页面全部数据,但原生的html代码我们无法直接使用,这时就需要用jsoup把他解析转换。
/**
* @Title: parseData
* @Description: TODO(解析页面数据转化为集合)
* @param html
* @param domain
* @return
* List<WeiboDomainGroup> 返回类型
*/
public List<WeiboDomain> parseData(String html){
List<WeiboDomain> result = new ArrayList<>();
Document doc = Jsoup.parse(html);
//处理填充数据
String str = "";
Elements scripts = doc.getElementsByTag("script");
//找到包含数据的script
for (int i=0;i<scripts.size();i++) {
String script = scripts.get(i).html();
if (script.contains("pl.content.signInPeople.index")) {
str = getHtml(script);
break;
}
}
//解析页面数据
doc = Jsoup.parse(str);
Elements user = doc.getElementsByTag("dd");
for (Element element : user){
if (element.attr("class").equals("mod_info S_line1")) {
WeiboDomain weiboDomainGroup = new WeiboDomain();
String uid = "";
Elements elements = element.getElementsByTag("div");
for (Element div : elements){
if (div.attr("class").equals("info_name W_fb W_f14")){
Element S_txt1 = div.getElementsByClass("S_txt1").get(0);
uid = S_txt1.attr("usercard").split("&")[0].replaceAll("id=", "");
weiboDomainGroup.setUid(uid);
weiboDomainGroup.setUrl(S_txt1.attr("href"));
weiboDomainGroup.setName(S_txt1.attr("title"));
Elements i = div.getElementsByTag("i");
for (Element ele : i){
if (ele.attr("class").equals("W_icon icon_member")){
weiboDomainGroup.setVip(true);
}
if (ele.attr("class").equals("W_icon icon_male")){
weiboDomainGroup.setGender("m");
}
else{
weiboDomainGroup.setGender("f");
}
}
}
if (div.attr("class").equals("info_connect")) {
Elements em = div.getElementsByTag("em");
weiboDomainGroup.setFriends_count(
Integer.parseInt(em.get(0).text()));
weiboDomainGroup.setFollowers_count(em.get(1).text());
weiboDomainGroup.setStatuses_count(
Integer.parseInt(em.get(2).text()));
}
if (div.attr("class").equals("info_add")){
Elements span = div.getElementsByTag("span");
weiboDomainGroup.setLocation(span.get(0).text());
}
if (div.attr("class").equals("info_intro")){
Elements span = div.getElementsByTag("span");
weiboDomainGroup.setDescription(span.get(0).text());
}
if (div.attr("class").equals("info_relation")){
String tag = div.text().split(":")[1];
weiboDomainGroup.setTag(tag);
}
}
weiboDomainGroup.setUpdateTime(LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
result.add(weiboDomainGroup);
}
}
return result;
}
/**
* @Title: getHtml
* @Description: TODO(微博数据是用FW.view填充,所以需要预处理)
* @return
* String 返回类型
*/
private String getHtml(String str) {
str = str.replaceAll("FM.view\\(", "").replaceAll("\\)", "");
JSONObject json = JSONObject.fromObject(str);
return json.getString("html");
}
第四步,测试
最后,我们稍微测试下,准确无误。over

四、模拟登录
以上的方法需要每次手动的从页面上复制cookie,这太麻烦了也无法自动化。因此一般我们都是通过模拟登录的方式自动获取cookie进行爬取。
本来是这样,不过,今天测试的时候发现自己以前写的模拟登录已经不可用了。我后面会讲怎么用另一种方法自动获取cookie。所以,这方面大家自己找资料吧,我也就不修复了。
五、代码
需要全部的代码可以联系我