Java爬蟲入門實戰:爬取京東圖書資訊
網路爬蟲框架
寫網路爬蟲,一個要有一個邏輯順序。本文主要講解我自己經常使用的一個順序,並且本人經常使用這個框架來寫一些簡單的爬蟲,複雜的爬蟲,也是在這個基礎上新增其他程式。
首先,我的工程都是使用maven建的。使用Spring MVC框架編寫過網站的同學,可以看出框架的重要性與邏輯性。在我的網路爬蟲框架中,包含的package有db、main、model、parse、util五個檔案。
db:主要放的是資料庫操作檔案,包含MyDataSource【資料庫驅動註冊、連線資料庫的使用者名稱、密碼】,MYSQLControl【連線資料庫,插入操作、更新操作、建表操作等】。
model:用來封裝物件,比如我要獲取京東書籍的ID、書名、價格,則需要在model寫入對應的屬性。說的直白一些,封裝的就是我要操作資料對應的屬性名。
util:主要放的是httpclient的內容,主要作用時將main方法,傳過來的url,通過httpclient相關方法,獲取需要解析的html檔案或者json檔案等。
parse:這裡面存放的是針對util獲取的檔案,進行解析,一般採用Jsoup解析;若是針對json資料,可採用正則表示式或者fastjson工具進行解析,建議使用fastjson,因其操作簡單,快捷。
main:程式起點,也是重點,獲取資料,執行資料庫語句,存放資料。
網路爬蟲的邏輯順序
針對我的網路爬蟲框架,網路爬蟲的邏輯順序,可以描述為:首先,main方法,將url傳給util獲取響應的html檔案,然後util將其獲得的html檔案,傳給parse進行解析,獲取最終資料,封裝在集合中。解析完畢後,資料返回到main,接著main操作db將資料匯入到mysql中。
網路爬蟲例項教學
通過上面的框架,我們可以看出寫一個網路爬蟲,其實很簡單(當然有很複雜的網路爬蟲哦)。下面,我將帶大家寫一個基於java爬蟲京東圖書資訊的網路爬蟲,只是做講解使用,供大家學習和參考。
首先,起點是什麼?你可能覺得是main方法,其實不然,起點是你要知道你要獲取網站中的哪些資料,然後針對要抓取的資料去寫model。如下圖,我要獲取京東上的圖書的價格,和圖書名,還有圖書的id(id是唯一標識,可作為資料表的主鍵)
model
用來封裝物件,我要抓取一本書的資料包括,書籍的id,書名及價格。ecliplse中生成set、get方法的快捷鍵是shift+alt+s然後選擇生成setter、getter
package model;
public class JdModel {
private String bookID;
private String bookName;
private String bookPrice;
public String getBookID() {
return bookID;
}
public void setBookID(String bookID) {
this.bookID = bookID;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getBookPrice() {
return bookPrice;
}
public void setBookPrice(String bookPrice) {
this.bookPrice = bookPrice;
}
}
main
主方法,儘量要求簡單,這裡我就這樣寫了。這裡面有註釋,很好理解。
package main;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import db.MYSQLControl;
import model.JdModel;
import util.URLFecter;
public class JdongMain {
//log4j的是使用,不會的請看之前寫的文章
static final Log logger = LogFactory.getLog(JdongMain.class);
public static void main(String[] args) throws Exception {
//初始化一個httpclient
HttpClient client = new DefaultHttpClient();
//我們要爬取的一個地址,這裡可以從資料庫中抽取資料,然後利用迴圈,可以爬取一個URL佇列
String url="http://search.jd.com/Search?keyword=Python&enc=utf-8&book=y&wq=Python&pvid=33xo9lni.p4a1qb";
//抓取的資料
List<JdModel> bookdatas=URLFecter.URLParser(client, url);
//迴圈輸出抓取的資料
for (JdModel jd:bookdatas) {
logger.info("bookID:"+jd.getBookID()+"\t"+"bookPrice:"+jd.getBookPrice()+"\t"+"bookName:"+jd.getBookName());
}
//將抓取的資料插入資料庫
MYSQLControl.executeInsert(bookdatas);
}
}
util
util中包含兩個檔案,URLFecter 與HTTPUtils,其中URLFecter 呼叫了HTTPUtils類。
package util;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.util.EntityUtils;
import model.JdModel;
import parse.JdParse;
public class URLFecter {
public static List<JdModel> URLParser (HttpClient client, String url) throws Exception {
//用來接收解析的資料
List<JdModel> JingdongData = new ArrayList<JdModel>();
//獲取網站響應的html,這裡呼叫了HTTPUtils類
HttpResponse response = HTTPUtils.getRawHtml(client, url);
//獲取響應狀態碼
int StatusCode = response.getStatusLine().getStatusCode();
//如果狀態響應碼為200,則獲取html實體內容或者json檔案
if(StatusCode == 200){
String entity = EntityUtils.toString (response.getEntity(),"utf-8");
JingdongData = JdParse.getData(entity);
EntityUtils.consume(response.getEntity());
}else {
//否則,消耗掉實體
EntityUtils.consume(response.getEntity());
}
return JingdongData;
}
}
上面程式呼叫的HTTPUtils這個類,以下是HTTPUtils這個類。
package util;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.message.BasicHttpResponse;
public abstract class HTTPUtils {
public static HttpResponse getRawHtml(HttpClient client, String personalUrl) {
//獲取響應檔案,即html,採用get方法獲取響應資料
HttpGet getMethod = new HttpGet(personalUrl);
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
HttpStatus.SC_OK, "OK");
try {
//執行get方法
response = client.execute(getMethod);
} catch (IOException e) {
e.printStackTrace();
} finally {
// getMethod.abort();
}
return response;
}
}
parse
parse主要是通過Jsoup來解析html檔案。並將解析後的資料,封裝在List集合中,將資料通過層層返回到main方法中。
package parse;
import java.util.ArrayList;
import java.util.List;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import model.JdModel;
/*
* 用於將上面傳下來的html解析,獲取我們需要的內容
* 解析方式,採用Jsoup解析,有不明白Jsoup的可以上網搜尋API文件
* Jsoup是一款很簡單的html解析器
*/
public class JdParse {
public static List<JdModel> getData (String html) throws Exception{
//獲取的資料,存放在集合中
List<JdModel> data = new ArrayList<JdModel>();
//採用Jsoup解析
Document doc = Jsoup.parse(html);
//獲取html標籤中的內容
Elements elements=doc.select("ul[class=gl-warp clearfix]").select("li[class=gl-item]");
for (Element ele:elements) {
String bookID=ele.attr("data-sku");
String bookPrice=ele.select("div[class=p-price]").select("strong").select("i").text();
String bookName=ele.select("div[class=p-name]").select("em").text();
//建立一個物件,這裡可以看出,使用Model的優勢,直接進行封裝
JdModel jdModel=new JdModel();
//物件的值
jdModel.setBookID(bookID);
jdModel.setBookName(bookName);
jdModel.setBookPrice(bookPrice);
//將每一個物件的值,儲存到List集合中
data.add(jdModel);
}
//返回資料
return data;
}
}
db
db中包含兩個java檔案,MyDataSource,MYSQLControl。這兩個檔案的作用已在前面說明了。
package db;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
public class MyDataSource {
public static DataSource getDataSource(String connectURI){
BasicDataSource ds = new BasicDataSource();
//MySQL的jdbc驅動
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUsername("root"); //所要連線的資料庫名
ds.setPassword("112233"); //MySQL的登陸密碼
ds.setUrl(connectURI);
return ds;
}
}
下面是MYSQLControl,主要使用QueryRunner方法操作資料庫,使用時是batch方法。
package db;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import model.JdModel;
/*
* Mysql操作的QueryRunner方法
* 一個數據庫操作類,別的程式直接呼叫即可
*/
public class MYSQLControl {
//根據自己的資料庫地址修改
static DataSource ds = MyDataSource.getDataSource("jdbc:mysql://127.0.0.1:3306/moviedata");
static QueryRunner qr = new QueryRunner(ds);
//第一類方法
public static void executeUpdate(String sql){
try {
qr.update(sql);
} catch (SQLException e) {
e.printStackTrace();
}
}
//第二類資料庫操作方法
public static void executeInsert(List<JdModel> jingdongdata) throws SQLException {
/*
* 定義一個Object陣列,行列
* 3表示列數,根據自己的資料定義這裡面的數字
* params[i][0]等是對陣列賦值,這裡用到集合的get方法
*
*/
Object[][] params = new Object[jingdongdata.size()][3];
for ( int i=0; i<params.length; i++ ){
params[i][0] = jingdongdata.get(i).getBookID();
params[i][1] = jingdongdata.get(i).getBookName();
params[i][2] = jingdongdata.get(i).getBookPrice();
}
qr.batch("insert into jingdongbook (bookID, bookName, bookPrice)"
+ "values (?,?,?)", params);
System.out.println("執行資料庫完畢!"+"成功插入資料:"+jingdongdata.size()+"條");
}
}
再看main方法
在main方法中有這樣一句程式,這便是呼叫了操作資料庫MYSQLControl程式,將抓取的資料插入到資料庫中了
MYSQLControl.executeInsert(bookdatas);
爬蟲效果展示
到此,便完成了這個簡單網路爬蟲的程式設計工作,下面來看看程式執行的結果吧。
資料庫中的結果如下:
(完)
PS:如果覺得我的分享不錯,歡迎大家隨手點贊、轉發。
原文:blog.csdn.net/qy20115549/article/details/52203722
Java團長
專注於Java乾貨分享
掃描上方二維碼獲取更多Java乾貨