Java爬取校内论坛新帖
Java爬取校內(nèi)論壇新帖
為了保持消息靈通,博主沒事會(huì)上上校內(nèi)論壇看看新帖,作為爬蟲愛好者,博主萌生了寫個(gè)爬蟲自動(dòng)下載的想法。
嗯,這次就選Java。
第三方庫(kù)準(zhǔn)備
- Jsoup
Jsoup是一款比較好的Java版HTML解析器。可直接解析某個(gè)URL地址、HTML文本內(nèi)容。它提供了一套非常省力的API,可通過(guò)DOM,CSS以及類似于jQuery的操作方法來(lái)取出和操作數(shù)據(jù)。
- mysql-connector-java
mysql-connector-java是java JDBC的MySQL驅(qū)動(dòng),可以提供方便統(tǒng)一的接口來(lái)操縱MySQL數(shù)據(jù)庫(kù)
爬蟲步驟
- 目標(biāo)分析
- 爬取網(wǎng)頁(yè)
- 解析網(wǎng)頁(yè)
- 存儲(chǔ)數(shù)據(jù)
目標(biāo)分析
博主爬取的是浙大的cc98論壇,需要內(nèi)網(wǎng)才能上,新帖會(huì)在其中一個(gè)版面內(nèi)出現(xiàn),界面大概是這樣:
分析一下之后,發(fā)現(xiàn)100條新帖一共有5頁(yè),內(nèi)容呈現(xiàn)在一張表格上。
再用Firefox分析一下頁(yè)面,發(fā)現(xiàn)是一個(gè)class="tableborder1"的table下有20行記錄,每一行有4個(gè)td,爬蟲只要獲取這四個(gè)td數(shù)據(jù)就可以了。
爬取網(wǎng)頁(yè)
由于這個(gè)網(wǎng)站是要用用戶名和密碼登錄的,博主一開始都在使用POST方法,后來(lái)用Firefox抓包分析之后,才發(fā)現(xiàn)可以使用帶cookies的GET方法登錄。
private void getDoc(String url, String page){try{//獲取網(wǎng)頁(yè)this.doc = Jsoup.connect(url).cookie("aspsky", "***").cookie("BoardList","BoardID=Show").cookie("owaenabled","True").cookie("autoplay","True").cookie("ASPSESSIONIDSSCBSSCR","***").data(" stype","3").data("page",page) //Page就是1-5頁(yè).get();}catch (IOException e){e.printStackTrace();throw new RuntimeException();}}這里使用到的Jsoup很強(qiáng)大,其實(shí)還可以添加header之類的作修飾,但博主發(fā)現(xiàn)只要加了cookies之后就能成功訪問(wèn)了。
解析網(wǎng)頁(yè)
根據(jù)目標(biāo)分析的結(jié)果,我們可以開始解析HTML文檔,同樣地,Jsoup允許使用JQuery方法來(lái)解析,十分方便
private void parse(){//采用JQuery CSS選擇Elements rows = doc.select(".tableborder1 tr");//去掉表頭行rows.remove(0);for(Element row : rows){String theme = row.select("td:eq(0) a:eq(1)").text().trim();String url = "http://www.cc98.org/"+ row.select("td:eq(0) a:eq(1)").attr("href");String part = row.select("td:eq(1) a").text().trim();String author = row.select("td:eq(2) a").text().trim();if(author.length()==0){author = "匿名";}String rawTime = row.select("td:eq(3)").text().replace("\n","").replace("\t","");try{Date publishTime = sdf.parse(rawTime);System.out.println(publishTime+" "+theme);System.out.println("---------------------------------------------------------");storage.store(theme,publishTime,part,author,url);}catch (ParseException e){e.printStackTrace();}}}存儲(chǔ)數(shù)據(jù)
為了方便日后的分析(博主還打算偶爾分析一下各個(gè)版面的活躍情況),我們要把數(shù)據(jù)存儲(chǔ)到硬盤上,這里選用了jdbc連接MySQL
public void store(String theme, Date publishTime,String part, String author,String url){try{String sql = "INSERT INTO news (theme," +"publishTime,part,author,url)VALUES(?,?,?,?,?)";//使用預(yù)處理的方法PreparedStatement ps = null;ps = conn.prepareStatement(sql);//依次填入?yún)?shù)ps.setString(1,theme);java.sql.Time time = new java.sql.Time(publishTime.getTime());//這里使用數(shù)據(jù)庫(kù)的時(shí)間戳ps.setTimestamp(2,new Timestamp(publishTime.getTime()));ps.setString(3,part);ps.setString(4,author);ps.setString(5,url);ps.executeUpdate();}catch (SQLException e){//主要是重復(fù)的異常,在MySQL中已經(jīng)有約束unique // e.printStackTrace();}}我們可以通過(guò)MySQL可視化工具查看結(jié)果,由于MySQLworkbench不太好用,博主使用了DBeaver,結(jié)果如下:
結(jié)果非常令人滿意。
完整代碼
Spider.java
package com.company;import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;public class Spider {private Document doc;//定義時(shí)間格式private SimpleDateFormat sdf = new SimpleDateFormat( "? yyyy/MM/dd? HH:mm?" );Storage storage = new Storage();private void getDoc(String url, String page){try{//獲取網(wǎng)頁(yè)this.doc = Jsoup.connect(url).cookie("aspsky", "***").cookie("BoardList","BoardID=Show").cookie("owaenabled","True").cookie("autoplay","True").cookie("ASPSESSIONIDSSCBSSCR","***").data(" stype","3").data("page",page).get();}catch (IOException e){e.printStackTrace();throw new RuntimeException();}}private void parse(){//采用JQuery CSS選擇Elements rows = doc.select(".tableborder1 tr");//去掉表頭行rows.remove(0);for(Element row : rows){String theme = row.select("td:eq(0) a:eq(1)").text().trim();String url = "http://www.cc98.org/"+ row.select("td:eq(0) a:eq(1)").attr("href");String part = row.select("td:eq(1) a").text().trim();String author = row.select("td:eq(2) a").text().trim();if(author.length()==0){author = "匿名";}String rawTime = row.select("td:eq(3)").text().replace("\n","").replace("\t","");try{Date publishTime = sdf.parse(rawTime);System.out.println(publishTime+" "+theme);System.out.println("---------------------------------------------------------");storage.store(theme,publishTime,part,author,url);}catch (ParseException e){e.printStackTrace();}}}public void run(String url){for (Integer i = 1; i<=5; i++){getDoc(url, i.toString());parse();}storage.close();}public static void main(String[] args){Spider spider = new Spider();spider.run("http://www.cc98.org/queryresult.asp?stype=3");} }Storage.java
package com.company;import java.sql.*; import java.util.Date;public class Storage {//數(shù)據(jù)庫(kù)連接字符串,cc98為數(shù)據(jù)庫(kù)名private static final String URL="jdbc:mysql://localhost:3306/cc98?characterEncoding=utf8&useSSL=false";//登錄名private static final String NAME="***";//密碼private static final String PASSWORD="***";private Connection conn = null;public Storage(){//加載jdbc驅(qū)動(dòng)try{Class.forName("com.mysql.jdbc.Driver");}catch (ClassNotFoundException e){System.out.println("未能成功加載驅(qū)動(dòng)程序,請(qǐng)檢查是否導(dǎo)入驅(qū)動(dòng)程序!");e.printStackTrace();}try{conn = DriverManager.getConnection(URL, NAME, PASSWORD); // System.out.println("獲取數(shù)據(jù)庫(kù)連接成功!");}catch (SQLException e){ // System.out.println("獲取數(shù)據(jù)庫(kù)連接失敗!");e.printStackTrace();}}public void close(){//關(guān)閉數(shù)據(jù)庫(kù)if(conn!=null){try{conn.close();}catch (SQLException e){e.printStackTrace();}}}public void store(String theme, Date publishTime,String part, String author,String url){try{String sql = "INSERT INTO news (theme," +"publishTime,part,author,url)VALUES(?,?,?,?,?)";//使用預(yù)處理的方法PreparedStatement ps = null;ps = conn.prepareStatement(sql);//依次填入?yún)?shù)ps.setString(1,theme);java.sql.Time time = new java.sql.Time(publishTime.getTime());//這里使用數(shù)據(jù)庫(kù)的時(shí)間戳ps.setTimestamp(2,new Timestamp(publishTime.getTime()));ps.setString(3,part);ps.setString(4,author);ps.setString(5,url);ps.executeUpdate();}catch (SQLException e){//主要是重復(fù)的異常,在MySQL中已經(jīng)有約束unique // e.printStackTrace();}} }小結(jié)
這個(gè)項(xiàng)目其實(shí)涉及的知識(shí)點(diǎn)還挺多的,博主也剛學(xué)java,很多細(xì)節(jié)也沒有很好吃透,如JDBC、Jsoup都值得好好學(xué)習(xí)一下。歡迎大家批評(píng)指正。
另,祝大家中秋國(guó)慶雙節(jié)快樂~
轉(zhuǎn)載于:https://www.cnblogs.com/fanghao/p/7629149.html
總結(jié)
以上是生活随笔為你收集整理的Java爬取校内论坛新帖的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MySQL之最基本命令
- 下一篇: IO Streams:缓冲流