听到“爬虫”,是不是第一时间想到Python/php ? 多少想玩爬虫的Java学习者就因为语言不通而止步。Java是真的不能做爬虫吗?
当然不是。
只不过python的3行代码能解决的问题,而Java要30行。
这里推荐大家一个大牛做的java爬虫框架 【WebMagic】
文档简单易懂!java爬虫开发的福利啊!
一起来动手做一个小应用吧!
爬虫小应用–知乎用户信息
爬虫思想有3步
1. 抽取目标链接
2. 抽取需要的信息
3. 处理数据
一、 抽取目标链接 (确定入口地址,这里的入口是https://www.zhihu.com/search?type=people&q=java)
接下来查看html结构,确定待爬取的目标链接。(这里我的目标链接是【前10个用户的详细信息页面的url】)
二、抽取需要的信息(webmagic提供了3种方式,xpath,css选择,正则表达式。具体可以查看下[WebMagic文档](http://webmagic.io/docs/zh/))
确定好【目标的信息】,如下图。
创建对应的实体对象
package entity;
/**
* 知乎用户信息
* @author antgan
*
*/
public class ZhihuUser {
private String key;//keyword
private String name;//用户名
private String identity;//身份
private String location;//所在地
private String profession;//行业
private int sex;//性别
private String school;//学校
private String major;//专业
private String recommend;//个人简介
private String picUrl;//头像url
private int agree;//赞同
private int thanks;//感谢
private int ask;//提问数
private int answer;//回答数
private int article;//文章数
private int collection;//收藏数
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdentity() {
return identity;
}
public void setIdentity(String identity) {
this.identity = identity;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getRecommend() {
return recommend;
}
public void setRecommend(String recommend) {
this.recommend = recommend;
}
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public int getAgree() {
return agree;
}
public void setAgree(int agree) {
this.agree = agree;
}
public int getThanks() {
return thanks;
}
public void setThanks(int thanks) {
this.thanks = thanks;
}
public int getAsk() {
return ask;
}
public void setAsk(int ask) {
this.ask = ask;
}
public int getAnswer() {
return answer;
}
public void setAnswer(int answer) {
this.answer = answer;
}
public int getArticle() {
return article;
}
public void setArticle(int article) {
this.article = article;
}
public int getCollection() {
return collection;
}
public void setCollection(int collection) {
this.collection = collection;
}
@Override
public String toString() {
return "ZhihuUser [name=" + name + ", identity=" + identity + ", location=" + location + ", profession="
+ profession + ", sex=" + sex + ", school=" + school + ", major=" + major + ", recommend=" + recommend
+ ", picUrl=" + picUrl + ", agree=" + agree + ", thanks=" + thanks + ", ask=" + ask + ", answer="
+ answer + ", article=" + article + ", collection=" + collection + "]";
}
}
编写PageProcessor(Processor中的process方法是webmagic的核心,负责抽取目标url的逻辑)
package repo;
import dao.ZhihuDao;
import dao.impl.ZhihuDaoImpl;
import entity.ZhihuUser;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
/**
* 知乎用户小爬虫<br>
* 输入搜索用户关键词(keyword),并把搜出来的用户信息爬出来<br>
* @date 2016-5-3
* @website ghb.soecode.com
* @csdn blog.csdn.net/antgan
* @author antgan
*
*/
public class ZhiHuUserPageProcessor implements PageProcessor{
//抓取网站的相关配置,包括:编码、抓取间隔、重试次数等
private Site site = Site.me().setRetryTimes(10).setSleepTime(1000);
//用户数量
private static int num = 0;
//搜索关键词
private static String keyword = "JAVA";
//数据库持久化对象,用于将用户信息存入数据库
private ZhihuDao zhihuDao = new ZhihuDaoImpl();
/**
* process 方法是webmagic爬虫的核心<br>
* 编写抽取【待爬取目标链接】的逻辑代码在html中。
*/
@Override
public void process(Page page) {
//1. 如果是用户列表页面 【入口页面】,将所有用户的详细页面的url放入target集合中。
if(page.getUrl().regex("https://www\\.zhihu\\.com/search\\?type=people&q=[\\s\\S]+").match()){
page.addTargetRequests(page.getHtml().xpath("//ul[@class='list users']/li/div/div[@class='body']/div[@class='line']").links().all());
}
//2. 如果是用户详细页面
else{
num++;//用户数++
/*实例化ZhihuUser,方便持久化存储。*/
ZhihuUser user = new ZhihuUser();
/*从下载到的用户详细页面中抽取想要的信息,这里使用xpath居多*/
/*为了方便理解,抽取到的信息先用变量存储,下面再赋值给对象*/
String name = page.getHtml().xpath("//div[@class='title-section ellipsis']/span[@class='name']/text()").get();
String identity = page.getHtml().xpath("//div[@class='title-section ellipsis']/span[@class='bio']/@title").get();
String location = page.getHtml().xpath("//div[@class='item editable-group']/span[@class='info-wrap']/span[@class='location item']/@title").get();
String profession = page.getHtml().xpath("//div[@class='item editable-group']/span[@class='info-wrap']/span[@class='business item']/@title").get();
boolean isMale = page.getHtml().xpath("//span[@class='item gender']/i[@class='icon icon-profile-male']").match();
boolean isFemale = page.getHtml().xpath("//span[@class='item gender']/i[@class='icon icon-profile-female']").match();
int sex = -1;
/*因为知乎有一部分人不设置性别 或者 不显示性别。所以需要判断一下。*/
if(isMale&&!isFemale) sex=1;//1代表男性
else if(!isMale&&isFemale) sex=0;//0代表女性
else sex=2;//2代表未知
String school = page.getHtml().xpath("//span[@class='education item']/@title").get();
String major = page.getHtml().xpath("//span[@class='education-extra item']/@title").get();
String recommend = page.getHtml().xpath("//span[@class='fold-item']/span[@class='content']/@title").get();
String picUrl = page.getHtml().xpath("//div[@class='body clearfix']/img[@class='Avatar Avatar--l']/@src").get();
int agree = Integer.parseInt(page.getHtml().xpath("//span[@class='zm-profile-header-user-agree']/strong/text()").get());
int thanks = Integer.parseInt(page.getHtml().xpath("//span[@class='zm-profile-header-user-thanks']/strong/text()").get());
int ask = Integer.parseInt(page.getHtml().xpath("//div[@class='profile-navbar clearfix']/a[2]/span[@class='num']/text()").get());
int answer = Integer.parseInt(page.getHtml().xpath("//div[@class='profile-navbar clearfix']/a[3]/span[@class='num']/text()").get());
int article = Integer.parseInt(page.getHtml().xpath("//div[@class='profile-navbar clearfix']/a[4]/span[@class='num']/text()").get());
int collection = Integer.parseInt(page.getHtml().xpath("//div[@class='profile-navbar clearfix']/a[5]/span[@class='num']/text()").get());
//对象赋值
user.setKey(keyword);
user.setName(name);
user.setIdentity(identity);
user.setLocation(location);
user.setProfession(profession);
user.setSex(sex);
user.setSchool(school);
user.setMajor(major);
user.setRecommend(recommend);
user.setPicUrl(picUrl);
user.setAgree(agree);
user.setThanks(thanks);
user.setAsk(ask);
user.setAnswer(answer);
user.setArticle(article);
user.setCollection(collection);
System.out.println("num:"+num +" " + user.toString());//输出对象
zhihuDao.saveUser(user);//保存用户信息到数据库
}
}
@Override
public Site getSite() {
return this.site;
}
public static void main(String[] args) {
long startTime ,endTime;
System.out.println("========知乎用户信息小爬虫【启动】喽!=========");
startTime = new Date().getTime();
//入口为:【https://www.zhihu.com/search?type=people&q=xxx 】,其中xxx 是搜索关键词
Spider.create(new ZhiHuUserPageProcessor()).addUrl("https://www.zhihu.com/search?type=people&q="+keyword).thread(5).run();
endTime = new Date().getTime();
System.out.println("========知乎用户信息小爬虫【结束】喽!=========");
System.out.println("一共爬到"+num+"个用户信息!用时为:"+(endTime-startTime)/1000+"s");
}
- 三、处理数据 (这里我存储在本地数据库中)
Dao层接口
package dao;
import entity.ZhihuUser;
/**
* 知乎 数据持久化 接口
* @author 甘海彬
*
*/
public interface ZhihuDao {
/**
* 保存用户信息
* @param user
* @return
*/
public int saveUser(ZhihuUser user);
}
Dao实现类
package dao.impl;
import java.util.ArrayList;
import java.util.List;
import dao.ZhihuDao;
import entity.ZhihuUser;
import util.DBHelper;
/**
* 知乎 数据库持久化接口 实现
* @author 甘海彬
*
*/
public class ZhihuDaoImpl implements ZhihuDao{
@Override
public int saveUser(ZhihuUser user) {
DBHelper dbhelper = new DBHelper();
StringBuffer sql = new StringBuffer();
sql.append("INSERT INTO spider_zhihu_user ( `key`,`name`,identity,location,profession,sex,school,major,recommend,picUrl,agree,thanks,ask,answer,article,collection)")
//`key`,`name`,identity,location,profession,sex,school,major,recommend,picUrl,agree,thanks,ask,answer,article,collection
.append("VALUES (? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? ) ");
//设置 sql values 的值
List<String> sqlValues = new ArrayList<>();
sqlValues.add(user.getKey());
sqlValues.add(user.getName());
sqlValues.add(user.getIdentity());
sqlValues.add(user.getLocation());
sqlValues.add(user.getProfession());
sqlValues.add(""+user.getSex());
sqlValues.add(user.getSchool());
sqlValues.add(user.getMajor());
sqlValues.add(user.getRecommend());
sqlValues.add(user.getPicUrl());
sqlValues.add(""+user.getAgree());
sqlValues.add(""+user.getThanks());
sqlValues.add(""+user.getAsk());
sqlValues.add(""+user.getAnswer());
sqlValues.add(""+user.getArticle());
sqlValues.add(""+user.getCollection());
int result = dbhelper.executeUpdate(sql.toString(), sqlValues);
return result;
}
}
这里我封装了个DbHelpler类,方便进行持久化操作,使用单例模式,并线程同步。
package util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* Mysql && SQL Server DBHelper
* @author antgan
*/
public class DBHelper {
public static final String driver_class = "com.mysql.jdbc.Driver";
public static final String driver_url = "jdbc:mysql://127.0.0.1/antgan?useunicode=true&characterEncoding=utf8";
public static final String user = "root";
public static final String password = "antgan";
private static Connection conn = null;
private PreparedStatement pst = null;
private ResultSet rst = null;
/**
* Connection
*/
public DBHelper() {
try {
conn = DBHelper.getConnInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 单例模式
* 线程同步
* @return
*/
private static synchronized Connection getConnInstance() {
if(conn == null){
try {
Class.forName(driver_class);
conn = DriverManager.getConnection(driver_url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("连接数据库成功");
}
return conn;
}
/**
* close
*/
public void close() {
try {
if (conn != null) {
DBHelper.conn.close();
}
if (pst != null) {
this.pst.close();
}
if (rst != null) {
this.rst.close();
}
System.out.println("关闭数据库成功");
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* query
*
* @param sql
* @param sqlValues
* @return ResultSet
*/
public ResultSet executeQuery(String sql, List<String> sqlValues) {
try {
pst = conn.prepareStatement(sql);
if (sqlValues != null && sqlValues.size() > 0) {
setSqlValues(pst, sqlValues);
}
rst = pst.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rst;
}
/**
* update
*
* @param sql
* @param sqlValues
* @return result
*/
public int executeUpdate(String sql, List<String> sqlValues) {
int result = -1;
try {
pst = conn.prepareStatement(sql);
if (sqlValues != null && sqlValues.size() > 0) {
setSqlValues(pst, sqlValues);
}
result = pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
/**
* sql set value
*
* @param pst
* @param sqlValues
*/
private void setSqlValues(PreparedStatement pst, List<String> sqlValues) {
for (int i = 0; i < sqlValues.size(); i++) {
try {
pst.setObject(i + 1, sqlValues.get(i));
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
噢!对了!表的创建sql也提供一下!
CREATE TABLE `spider_zhihu_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(30) DEFAULT NULL,
`name` varchar(30) DEFAULT NULL,
`identity` varchar(100) DEFAULT NULL,
`location` varchar(20) DEFAULT NULL,
`profession` varchar(30) DEFAULT NULL,
`sex` int(2) DEFAULT NULL,
`school` varchar(30) DEFAULT NULL,
`major` varchar(30) DEFAULT NULL,
`recommend` varchar(100) DEFAULT NULL,
`picUrl` varchar(255) DEFAULT NULL,
`agree` int(11) DEFAULT NULL,
`thanks` int(11) DEFAULT NULL,
`ask` int(11) DEFAULT NULL,
`answer` int(11) DEFAULT NULL,
`article` int(11) DEFAULT NULL,
`collection` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8;
以上就是全部代码。
进行测试。
基于webmagic的爬虫小应用--爬取知乎用户信息的更多相关文章
-
爬虫(十六):scrapy爬取知乎用户信息
一:爬取思路 首先我们应该找到一个账号,这个账号被关注的人和关注的人都相对比较多的,就是下图中金字塔顶端的人,然后通过爬取这个账号的信息后,再爬取他关注的人和被关注的人的账号信息,然后爬取被关注人的账 ...
-
利用 Scrapy 爬取知乎用户信息
思路:通过获取知乎某个大V的关注列表和被关注列表,查看该大V和其关注用户和被关注用户的详细信息,然后通过层层递归调用,实现获取关注用户和被关注用户的关注列表和被关注列表,最终实现获取大量用户信息. 一 ...
-
Srapy 爬取知乎用户信息
今天用scrapy框架爬取一下所有知乎用户的信息.道理很简单,找一个知乎大V(就是粉丝和关注量都很多的那种),找到他的粉丝和他关注的人的信息,然后分别再找这些人的粉丝和关注的人的信息,层层递进,这样下 ...
-
爬虫实战--利用Scrapy爬取知乎用户信息
思路: 主要逻辑图:
-
[Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
转载自:http://blog.csdn.net/eastmount/article/details/51231852 一. 文章介绍 源码下载地址:http://download.csdn.net/ ...
-
python3编写网络爬虫22-爬取知乎用户信息
思路 选定起始人 选一个关注数或者粉丝数多的大V作为爬虫起始点 获取粉丝和关注列表 通过知乎接口获得该大V的粉丝列表和关注列表 获取列表用户信息 获取列表每个用户的详细信息 获取每个用户的粉丝和关注 ...
-
使用python scrapy爬取知乎提问信息
前文介绍了python的scrapy爬虫框架和登录知乎的方法. 这里介绍如何爬取知乎的问题信息,并保存到mysql数据库中. 首先,看一下我要爬取哪些内容: 如下图所示,我要爬取一个问题的6个信息: ...
-
[python爬虫] Selenium定向爬取PubMed生物医学摘要信息
本文主要是自己的在线代码笔记.在生物医学本体Ontology构建过程中,我使用Selenium定向爬取生物医学PubMed数据库的内容. PubMed是一个免费的搜寻引擎,提供生物医学方 ...
-
Python爬虫根据关键词爬取知网论文摘要并保存到数据库中【入门必学】
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:崩坏的芝麻 由于实验室需要一些语料做研究,语料要求是知网上的论文摘要 ...
随机推荐
-
vim使用命令
* 向前搜索当前单词 # 向后搜索当前单词 n 和 shift n(N) 向后向前跳到所匹配的单词处 C-f page down; C-b page up C-o 回到上次位置 C-i &qu ...
-
python 参数
摘自:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00137473844933 ...
-
ARM指令和Thumb指令区别
Thumb指令集 ]的问题而提出的,它具有16为的代码密度.Thumb不是一个完整的体系结构,不能指望处理程序只执行Thumb指令而不支持ARM指令集.因此,Thumb指令只需要支持通用功能,必要时, ...
-
USACO 1.3.3 Prime Cryptarithm
题目链接:1.3.3 我用的枚举法,即每产生一组数据就判断是否是所给数字里的. AC还沾沾自喜,但一看题解,发现自己的代码真low... 在平时练习时,应该追求高效,精炼的代码,这样比赛时才能省出大量 ...
-
使用 EclEmma 进行覆盖测试
开源软件测试工具 EclEmma,它能够对由 Java 语言编写的程序进行覆盖测试,从而对程序运行的结果生成详尽的覆盖测试报告. UT-Junit 安装 EclEmma 插件 安装 EclEmma 插 ...
-
Hive:把一段包含中文的sql脚本粘贴到beeline client运行中文乱码
背景: 在做项目过程中不可能hive表中都是非中文字段.在最近做的项目中就遇到需要在beeline界面上执行查询脚本,但脚本中包含中文,正常一个脚本用文本写好后,粘贴到beeline窗口运行时,发现中 ...
-
CString比较不区分大小写
第一种:都变为大写 或者都变成小写. str1.MakeUpper();str2.MakeUpper();or:str1.MakeLower();str2.MakeLower(); if(str1== ...
-
NULL - AUTO_INCREMENT
http://dev.mysql.com/doc/refman/5.7/en/create-table.html Data Types and Attributes for Columns data_ ...
-
20155226 《网络对抗》Exp 8 Web基础
20155226 <网络对抗>Exp 8 Web基础 实践内容 1.Web前端HTML 配置环境 正常安装.启动Apache 安装:sudo apt-get install apache2 ...
-
饭后来份TempData,瞅瞅有啥料
原本打算写一篇关于.NET下的分布式缓存的随笔,但是为了举一个实际的运用,就想把控制器(是ASP.NET MVC的)中的Session替换成使用分布式缓存来实现.如果你的网站最后是需要负载均衡的话,这 ...