Java多线程网络爬虫时光网为例.docx
《Java多线程网络爬虫时光网为例.docx》由会员分享,可在线阅读,更多相关《Java多线程网络爬虫时光网为例.docx(15页珍藏版)》请在冰豆网上搜索。
Java多线程网络爬虫时光网为例
Java多线程网络爬虫(时光网为例)
多线程简介
Java多线程实现方式主要有三种:
继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。
其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
本文所采用的方法是继承Thread类的方法,Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例。
启动线程的唯一方法就是通过Thread类的start()实例方法。
start()方法是一个native方法,它将启动一个新线程,并执行run()方法。
这种方式实现多线程很简单,通过自己的类直接extendThread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
多线程网络爬虫
为了加快爬虫速度,可以采用多线程网络爬虫的方法。
以下我以时光网为例,写一个简单的网络爬虫。
分析要爬的数据
如下面数据,为我爬的一些电影预告片的初始信息,存在数据库movie的这张表中。
下表是我所要爬的预告片相关的数据,包括预告片的id(prmovieId),预告片的链接(url),预告片对应的电影id(movieId),预告片的标题(title)。
后面会在model框架中,你会发现,我会把这些待爬取的数据封装在MtimeModel中。
网络抓包
通过网络抓包的方式,查看数据的获取方式、方法。
即真实请求的地址及返回数据的格式(htmlorjson).
爬虫框架
如果想了解,为什么这样写,请看我前面的介绍网络爬虫框架的文章。
model
model里面主要写了三个,我们需要的,一个是MtimeUrl封装的是数据库movie这张表中某些数据对应的信息。
MtimeModel封装的是需要爬取数据的信息。
packageorg.autodata.model;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
publicclassMtimeUrl{
//待爬取电影的id和对应的连接
privateStringid;
privateStringurl;
publicStringgetId(){
returnid;
}
publicvoidsetId(Stringid){
this.id=id;
}
publicStringgetUrl(){
returnurl;
}
publicvoidsetUrl(Stringurl){
this.url=url;
}
}
爬取的数据为:
packageorg.autodata.model;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
publicclassMtimeModel{
privateStringprmovieId;
privateStringurl;
privateStringmovieId;
privateStringtitle;
publicStringgetPrmovieId(){
returnprmovieId;
}
publicvoidsetPrmovieId(StringprmovieId){
this.prmovieId=prmovieId;
}
publicStringgetUrl(){
returnurl;
}
publicvoidsetUrl(Stringurl){
this.url=url;
}
publicStringgetMovieId(){
returnmovieId;
}
publicvoidsetMovieId(StringmovieId){
this.movieId=movieId;
}
publicStringgetTitle(){
returntitle;
}
publicvoidsetTitle(Stringtitle){
this.title=title;
}
}
Json数据的解析model
packageorg.autodata.model;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
publicclassJsonModel{
privateStringVideoID;
privateStringMovieID;
privateStringShortTitle;
privateStringprmovieId;
privateStringurl;
publicStringgetVideoID(){
returnVideoID;
}
publicStringgetShortTitle(){
returnShortTitle;
}
publicvoidsetShortTitle(StringshortTitle){
ShortTitle=shortTitle;
}
publicStringgetPrmovieId(){
returnprmovieId;
}
publicvoidsetPrmovieId(StringprmovieId){
this.prmovieId=prmovieId;
}
publicStringgetUrl(){
returnurl;
}
publicvoidsetUrl(Stringurl){
this.url=url;
}
publicvoidsetVideoID(StringvideoID){
VideoID=videoID;
}
publicStringgetMovieID(){
returnMovieID;
}
publicvoidsetMovieID(StringmovieID){
MovieID=movieID;
}
}
MtimeThread主方法
主方法里为了方便,我直接使用的是Jsoup去请求数据,建议大家还是使用httpclient,因为有时候Jsoup是失灵的。
packageorg.autodata.navi.main;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
importjava.io.IOException;
importjava.sql.SQLException;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjavax.sql.DataSource;
importmons.dbutils.QueryRunner;
importmons.dbutils.ResultSetHandler;
importmons.dbutils.handlers.BeanListHandler;
importorg.autodata.db.MyDataSource;
importorg.autodata.model.MtimeModel;
importorg.autodata.model.MtimeUrl;
importorg.autodata.parse.MtimeParse;
importorg.jsoup.Jsoup;
importorg.jsoup.nodes.Document;
publicclassMtimeThreadextendsThread{
publicstaticDataSourceds=MyDataSource.getDataSource("jdbc:
mysql:
//127.0.0.1:
3306/moviedata");
publicstaticQueryRunnerqr=newQueryRunner(ds);
StringStarturl="";
StringId="";
//构造函数,初始化使用
publicMtimeThread(StringStarturl,StringId){
this.Starturl=Starturl;
this.Id=Id;
}
publicvoidrun(){
Listmoviedatas=newArrayList();
//这里采用jsoup直接模拟访问网页
try{
Documentdoc=Jsoup.connect(Starturl).userAgent("bbb").timeout(120000).get();
moviedatas=MtimeParse.getData(doc);
}catch(IOExceptione){
e.printStackTrace();
}
for(MtimeModelmt:
moviedatas){
System.out.println("prmovieId:
"+mt.getPrmovieId()+"movieId:
"+mt.getMovieId()+"Title:
"+mt.getTitle()
+"url:
"+mt.getUrl());
}
try{
MYSQLControl.executeUpdate(moviedatas,Id);
}catch(SQLExceptione){
e.printStackTrace();
}
}
publicstaticvoidmain(String[]args)throwsSQLException{
ResultSetHandler>h=newBeanListHandler(MtimeUrl.class);
ListStarturls=qr.query("SELECTid,urlFROMmoviedata.movieWHEREwebsite='时光网'andis_crawler=0",h);
//创建固定大小的线程池
ExecutorServiceexec=Executors.newFixedThreadPool(5);
for(MtimeUrlStart:
Srturls){
//执行线程
exec.execute(newMtimeThread(Start.getUrl(),Start.getId()));
}
//线程关闭
exec.shutdown();
}
}
MtimeParse解析数据
packageorg.autodata.parse;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
importjava.util.ArrayList;
importjava.util.List;
importjava.util.regex.Matcher;
importjava.util.regex.Pattern;
importorg.autodata.model.JsonModel;
importorg.autodata.model.MtimeModel;
importorg.jsoup.nodes.Document;
importcom.alibaba.fastjson.JSON;
publicclassMtimeParse{
publicstaticListgetData(Documentdoc){
ListmtimeData=newArrayList();
//获取待解析的html文件
Stringhtml=doc.html();
//fastJson测试
//justcontainthepreview
ListmtimeJsonData=newArrayList();
Patterndata1=Ppile("预告片\":
(.*?
)\\,(\"拍摄花絮|\"精彩片段)");
MatcherdataMatcher1=data1.matcher(html);
Stringda1="";
while(dataMatcher1.find()){
//待解析的json字符串
da1=dataMatcher1.group
(1);
}
if(da1.length()!
=0){
Listjsonmodel1=JSON.parseArray(da1,JsonModel.class);
for(JsonModeljso:
jsonmodel1){
JsonModelmtimeModel=newJsonModel();
StringVideoID="mtime"+jso.getVideoID();
StringMovieID="mtime"+jso.getMovieID();
StringShortTitle=jso.getShortTitle();
Stringurl="
mtimeModel.setPrmovieId(VideoID);
mtimeModel.setUrl(url);
mtimeModel.setMovieID(MovieID);
mtimeModel.setShortTitle(ShortTitle);
mtimeJsonData.add(mtimeModel);
}
}
returnmtimeData;
}
}
数据库操作
MyDataSource
packageorg.autodata.db;
importjavax.sql.DataSource;
importmons.dbcp2.BasicDataSource;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
publicclassMyDataSource{
publicstaticDataSourcegetDataSource(StringconnectURI){
BasicDataSourceds=newBasicDataSource();
//MySQL的jdbc驱动
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUsername("root");//所要连接的数据库名
ds.setPassword("112233");//MySQL的登陆密码
ds.setUrl(connectURI);
returnds;
}
}
packageorg.autodata.db;
importjava.sql.SQLException;
importjava.util.List;
importjavax.sql.DataSource;
importmons.dbutils.QueryRunner;
importmons.logging.Log;
importmons.logging.LogFactory;
importorg.autodata.model.MtimeCommentModel;
importorg.autodata.model.MtimeModel;
/*
*author:
合肥工业大学管院学院钱洋
*1563178220@
*/
publicclassMYSQLControl{
staticfinalLoglogger=LogFactory.getLog(MYSQLControl.class);
staticDataSourceds=MyDataSource.getDataSource("jdbc:
mysql:
//127.0.0.1:
3306/moviedata");
staticQueryRunnerqr=newQueryRunner(ds);
//第一类方法
publicstaticvoidexecuteUpdate(Stringsql){
try{
qr.update(sql);
}catch(SQLExceptione){
logger.error(e);
}
}
//第二类数据库操作方法
publicstaticvoidexecuteUpdate(Listmoviedata,Stringid)throwsSQLException{
//定义一个Object数组,行列
Object[][]params=newObject[moviedata.size()][4];
for(inti=0;iparams[i][0]=moviedata.get(i).getPrmovieId();
params[i][1]=moviedata.get(i).getMovieId();
params[i][2]=moviedata.get(i).getUrl();
params[i][3]=moviedata.get(i).getTitle();
}
try{
qr.batch("insertintomovieURL(prmovieId,movieId,url,title)"
+"values(?
?
?
?
)",params);
qr.update("updatemoviesetis_crawler=1whereid='"+id+"'");
}catch(Exceptione){
logger.error(e);
}
}
//操作评论的数据库
publicstaticvoidexecuteUpdate1(Listmoviedata,Stringid)throwsSQLException{
Object[][]params=newObject[moviedata.size()][3];
for(inti=0;iparams[i][0]=moviedata.get(i).getComm_id();
params[i][1]=moviedata.get(i).getComment();
params[i][2]=moviedata.get(i).getTime();
}
try{
qr.batch("insertintomoviecomment(comm_id,prmovieId,comment,time)"
+"values(?
'"+id+"',?
?
)",params);
qr.update("updatemovieurlsetis_crawler=1whereprmovieId='"+id+"'");
}catch(Exceptione){
logger.error(e);
}
}
}