網絡爬蟲框架

寫網絡爬蟲,一個要有一個邏輯順序。本文主要講解我自己經常使用的一個順序,並且本人經常使用這個框架來寫一些簡單的爬蟲,複雜的爬蟲,也是在這個基礎上添加其他程序。

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是唯一標識,可作爲數據表的主鍵)

Java爬蟲入門實戰:爬取京東圖書信息

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 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 URLParser (HttpClient client, String url) throws Exception {

//用來接收解析的數據

List JingdongData = new ArrayList();

//獲取網站響應的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 getData (String html) throws Exception{

//獲取的數據,存放在集合中

List data = new ArrayList();

//採用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 jingdongdata) throws SQLException {

/*

* 定義一個Object數組,行列

* 3表示列數,根據自己的數據定義這裏面的數字

* params[i][0]等是對數組賦值,這裏用到集合的get方法

*

*/

Object[][] params = new Object[jingdongdata.size()][3];

for ( int i=0; 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);

爬蟲效果展示

到此,便完成了這個簡單網絡爬蟲的編程工作,下面來看看程序運行的結果吧。

Java爬蟲入門實戰:爬取京東圖書信息

數據庫中的結果如下:

Java爬蟲入門實戰:爬取京東圖書信息


原文:blog.csdn.net/qy20115549/article/details/52203722

相关文章