20161119 写
本次项目工程:
第一部分:https://github.com/RenjiaLu9527/WebMagic_test-20161119—mysq
第二部分:https://github.com/RenjiaLu9527/JFreeChart-20161119/
相关博客、论坛网站链接如下
WebMagic简单灵活的爬虫框架。http://webmagic.io
WebCollector JAVA爬虫框架 http://www.oschina.net/p/webcollector?fromerr=WSgeV8m4
给推荐几个github上优秀的java爬虫项目?【知乎】
83款 网络爬虫开源软件
利用WebMagic的Cookie机制进行页面爬取
DwyaneWade NBA球星德维恩·韦德 的新浪微博
java实现各种数据统计图(柱形图,饼图,折线图)
JFreechart 1.0.19开源包下载链接
一键将正则表达式转换为JAVA python等语言的字符串:
正则表达式测试工具/常用正则表达式/正则代码生成 - 在线工具
一个星期多一点,在众多的爬虫框架中选择了Webmagic,WebMagic简单灵活的爬虫框架。
简单易用,在这之前用的是WebCollector JAVA爬虫框架,它的模块划分弄了一天也没搞清楚,文档没有webmagic的全,上手太慢,所以放弃
webmagic是国人做的,目前我使用的功能很少,对其框架的扩展定制内容很少,感觉不出什么优点来,基本功能使用上手很快
有个概念:
分布式:一个业务分拆多个子业务,部署在不同的服务器上
集群:同一个业务,部署在多个服务器上
爬虫可以做很多事,将网络上感兴趣的资源通过爬虫大规模的抓取,然后进行分析等其他操作,可以做出很多有意思的东西,比如‘舆情分析系统’‘网络环境文明用语情况分析’还可以‘爬取某个网站的图片、文字、视频’相当于一键直接下载,非常方便;
我做的这个小模型是
webmagic框架爬虫抓取某位微博用户的每条微博
下载保存本地并储存到本地数据库Mysql
调用Watson的Tone Analyzer API逐条分析本地数据库的数据并收集分析Json结果
用JAVA GUI显示情感变化趋势
四部分,
前两部分由于微博网站页面的显示方式是由 JSP 函数获取显示的,导致webmagic的xpath和css无法正常使用,还有他的正则表达式解析也不正常;最后不得不放弃这三个函数,老老实实的用java自带的正则解析函数才解析正常,
1 大概了解网页的构成
2 webmagic熟悉基本用法(官网文档很详细)
3 JDBC等连接数据库的操作 和数据库的基本使用
4 正这表达式(重点!好好研究)
5 还是 get/post方法 和 Json解析
6 学会调用开源库 开源模板,比如这个折线图开源包
先分析网页的构成 然后再测试抓取是否成功。
这里我以 DwyaneWade NBA球星德维恩·韦德的微博为例 抓取
我将第一第二步建了一个工程 webmagic_test,第三第四步也建立一个工程JFreeChart;两个工程分开运行
webmagic_test工程目录如下
JFreeChart工程目录如下
笔记
webmagic框架的两个java文件SinaBlogProcessor.java****OneFilePipeline.java
代码如下:
SinaBlogProcessor.java
package main;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import us.codecraft.webmagic.downloader.Downloader;
import java.util.ArrayList;
import java.util.List;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.FilePipeline;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;
/**
* @author [email protected]
*/
public class SinaBlogProcessor implements PageProcessor {
public static String PATHNAME = "H:/php/wamp/wamp/www/_webmagicdata/weibodata_jdbc/jdbc_weibodata_page";
private static long userNum = 0;
private static String userId = "";
private Site siteold = Site.me().setSleepTime(3000);// .setUserAgent(
// "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like
// Gecko) Chrome/45.0.2454.101 Safari/537.36");
private volatile static int maini = 0;
private Site site = new Site().setRetryTimes(3).setSleepTime(2000).setTimeOut(10000)
// 添加cookie之前一定要先设置主机地址,否则cookie信息不生效
.setDomain(".weibo.com")
// 添加抓包获取的cookie信息(某些网站如果没有设定cookice无法访问)
.addCookie("Apache", "6047605616040.527.1448080352314")
/*如何添加 cookice:[http://blog.csdn.net/kingsonyoung/article/details/51753639]
*/
// 添加请求头,有些网站会根据请求头判断该请求是由浏览器发起还是由爬虫发起的
.addHeader("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.245")
.addHeader("Accept", "*/*").addHeader("Accept-Encoding", "gzip, deflate, sdch")
.addHeader("Accept-Language", "zh-CN,zh;q=0.8").addHeader("Connection", "keep-alive").addHeader("Referer",
"http://weibo.com/p/1003062264358493/home?is_search=0&visible=0&is_all=1&is_tag=0&profile_ftype=1&page=1#feedtop");
@Override
public void process(Page page) {
String str = "" + page.getUrl().toString();
// System.out.println("#1");
if (str.indexOf("#feedtop") >= 0) {
// System.out.println("#2");
if (page.getHtml().toString().indexOf("抱歉,你访问的页面地址有误,或者该页面不存在") < 0
&& page.getHtml().toString().indexOf("请检查输入的网址是否正确") < 0
&& page.getHtml().toString().indexOf("网络繁忙") < 0
&& page.getHtml().toString().indexOf("请稍后再试") < 0) {
// System.out.println("#3");
str = str.substring(0, str.indexOf("#feedtop"));
str = str.substring(str.indexOf("&page=") + 6, str.length());
int cnt = 0;
int pagenum = Integer.parseInt(str);
System.out.println("pagenum=" + pagenum);
// 获取页数
String xialaURL1 = "http://weibo.com/p/aj/v6/mblog/mbloglist?ajwvr=6&domain=100505&is_search=0&visible=0&is_all=1&is_tag=0&profile_ftype=1"
+ "&page=" + pagenum + "&pagebar=0" + "&pl_name=Pl_Official_MyProfileFeed__23&id=" + userId
+ "&script_uri=/p/" + userId + "/home&feed_type=0" + "&pre_page=" + pagenum
+ "&domain_op=100505&__rnd=1479123380183";
String xialaURL2 = "http://weibo.com/p/aj/v6/mblog/mbloglist?ajwvr=6&domain=100505&is_search=0&visible=0&is_all=1&is_tag=0&profile_ftype=1"
+ "&page=" + pagenum + "&pagebar=1" + "&pl_name=Pl_Official_MyProfileFeed__23&id=" + userId
+ "&script_uri=/p/" + userId + "/home&feed_type=0" + "&pre_page=" + pagenum
+ "&domain_op=100505&__rnd=1479123380183";
List listurl = new ArrayList();
listurl.add(xialaURL1);
listurl.add(xialaURL2);
page.addTargetRequests(listurl);
page.putField("[Chushiyemian]", page.getHtml());
} else {
System.out.println("userId=" + userId + "页面不存在 404");
// userId++;
maini = -1;
}
} else {
// 两个下拉刷新页面
page.putField("[Xialashuaxin]", page.getJson());
if (page.getJson().toString().indexOf("WB_feed_detail clearfix") < 0) {
maini = -1;
System.out.println("userId=" + userId + "到达最后一页");
}
}
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
// http://weibo.com/p/1005055317970558/home?
// http://weibo.com/kevindurant?is_search=0&visible=0&is_all=1&is_tag=0&profile_ftype=1&page=2#feedtop
// http://weibo.com/p/1003061735538085/home?from=page_100306_profile&wvr=6&mod=data&is_all=1#place
for (userNum = 93; userNum < 99; userNum++) {
userId = "10030622643584" + userNum;
PATHNAME = "H:/php/wamp/wamp/www/_webmagicdata/weibodata_jdbc/" + userId + "jdbc_weibodata_page";
OneFilePipeline.cnt = 0;// 置0
String pageURLs = "http://weibo.com/p/" + userId
+ "/home?is_search=0&visible=0&is_all=1&is_tag=0&profile_ftype=1&page=";// 1#feedtop";
String pageURLe = "#feedtop";
String xialaPagebars = "";
for (maini = 1; maini <= 999 && maini > 0; maini++) {
try {
Spider.create(new SinaBlogProcessor())
// .addUrl("http://weibo.com/languageexchange?refer_flag=1001030201_&is_all=1")
// .addPipeline(new
// FilePipeline("H:/php/wamp/wamp/www/_webmagicdata"))
.addPipeline(new OneFilePipeline(PATHNAME)).addUrl(pageURLs + maini + pageURLe).thread(50)
.run();
} catch (FileNotFoundException | UnsupportedEncodingException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
System.out.println("userId=" + userId + "处理完毕/n传送至watson分析并返回显示");
}
}
// @Override
// public void process(ResultItems arg0, Task arg1) {
// // TODO 自动生成的方法存根
// System.out.println("process 2参数函数"+arg0.get("content1"));
//
// }1005053610038332
}
注意添加 cookice才能正常访问微博,每个人的不同,此处不贴出来了
OneFilePipeline.java
package main;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.utils.FilePersistentBase;
import utils.Jdbc;
import java.io.*;
import java.util.Map;
/**
* @author [email protected]
*/
public class OneFilePipeline extends FilePersistentBase implements Pipeline {
public static int cnt = 0;
private Logger logger = LoggerFactory.getLogger(getClass());
private PrintWriter printWriter;
/**
* create a FilePipeline with default path"/data/webmagic/"
*/
public OneFilePipeline() throws FileNotFoundException, UnsupportedEncodingException {
this("/data/webmagic/");
// this("H:\php\wamp\wamp\www/_webmagicdata/");
}
public OneFilePipeline(String path) throws FileNotFoundException, UnsupportedEncodingException {
setPath(path);
printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(getFile(path)), "UTF-8"));
}
@Override
public synchronized void process(ResultItems resultItems, Task task) {
printWriter.println("url:\t" + resultItems.getRequest().getUrl());
for (Map.Entry entry : resultItems.getAll().entrySet()) {
if (entry.getValue() instanceof Iterable) {
Iterable value = (Iterable) entry.getValue();
printWriter.println(entry.getKey() + ":");
for (Object o : value) {
printWriter.println(o);
}
} else {
new Jdbc();
printWriter.println(entry.getKey() + ":\t" + entry.getValue());
// 先保存 再处理本地
Jdbc.saveToMysql(Jdbc.parseData(entry.getValue()));
}
}
printWriter.flush();
}
@Override
public java.io.File getFile(java.lang.String fullName) {
cnt++;
System.out.println("fullname=" + fullName + cnt);
return new File(fullName + cnt);
}
}
模块划分很清楚,不多说
一段很长的正则:
//////////////////////////////////////////////////////////////////////
1 获取 正常微博文字
网页代码
\"WB_text W_f14\" node-type=\"feed_list_content\" nick-name=\"DwyaneWade\">\n Game day! - 比赛日! <\/div>
正则表达式
(?<=(\Wclass=\\"WB_text\WW_f14\\"\Wnode-type=\\"feed_list_content\\"\Wnick-name=\\"\w+\\">\\n)).*?(?=<(\\\/div>))
2 转发别人的微博时,没有nick-name=\”DwyaneWade\”
网页代码