JAVA微博爬虫基础篇——简单的微博爬虫(手动cookie)

3,661 阅读5分钟

系列目录:

JAVA微博爬虫基础篇——简单的微博爬虫(手动cookie)

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。所以,这方面大家自己找资料吧,我也就不修复了。

五、代码

需要全部的代码可以联系我