zoukankan      html  css  js  c++  java
  • Java爬取校内论坛新帖

    Java爬取校内论坛新帖

    为了保持消息灵通,博主没事会上上校内论坛看看新帖,作为爬虫爱好者,博主萌生了写个爬虫自动下载的想法。

    嗯,这次就选Java。

    第三方库准备

    • Jsoup

    Jsoup是一款比较好的Java版HTML解析器。可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

    • mysql-connector-java

    mysql-connector-java是java JDBC的MySQL驱动,可以提供方便统一的接口来操纵MySQL数据库

    爬虫步骤

    • 目标分析
    • 爬取网页
    • 解析网页
    • 存储数据

    目标分析

    博主爬取的是浙大的cc98论坛,需要内网才能上,新帖会在其中一个版面内出现,界面大概是这样:

    分析一下之后,发现100条新帖一共有5页,内容呈现在一张表格上。

    再用Firefox分析一下页面,发现是一个class="tableborder1"的table下有20行记录,每一行有4个td,爬虫只要获取这四个td数据就可以了。

    爬取网页

    由于这个网站是要用用户名和密码登录的,博主一开始都在使用POST方法,后来用Firefox抓包分析之后,才发现可以使用带cookies的GET方法登录。

    private void getDoc(String url, String page)
        {
            try
            {
                //获取网页
                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页
                        .get();
            }
            catch (IOException e)
            {
                e.printStackTrace();
                throw new RuntimeException();
            }
        }
    

    这里使用到的Jsoup很强大,其实还可以添加header之类的作修饰,但博主发现只要加了cookies之后就能成功访问了。

    解析网页

    根据目标分析的结果,我们可以开始解析HTML文档,同样地,Jsoup允许使用JQuery方法来解析,十分方便

    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("
    ","")
                        .replace("	","");
                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();
                }
            }
        }
    

    存储数据

    为了方便日后的分析(博主还打算偶尔分析一下各个版面的活跃情况),我们要把数据存储到硬盘上,这里选用了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(?,?,?,?,?)";
                
                //使用预处理的方法
                PreparedStatement ps = null;
    
                ps = conn.prepareStatement(sql);
    
                //依次填入参数
                ps.setString(1,theme);
                java.sql.Time time = new java.sql.Time(publishTime.getTime());
                //这里使用数据库的时间戳
                ps.setTimestamp(2,new Timestamp(publishTime.getTime()));
                ps.setString(3,part);
                ps.setString(4,author);
                ps.setString(5,url);
    
                ps.executeUpdate();
            }
            catch (SQLException e)
            {
                //主要是重复的异常,在MySQL中已经有约束unique
    //            e.printStackTrace();
            }
        }
    

    我们可以通过MySQL可视化工具查看结果,由于MySQLworkbench不太好用,博主使用了DBeaver,结果如下:

    结果非常令人满意。

    完整代码

    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;
        //定义时间格式
        private SimpleDateFormat sdf =   new SimpleDateFormat( "  yyyy/MM/dd  HH:mm " );
        Storage storage = new Storage();
    
        private void getDoc(String url, String page)
        {
            try
            {
                //获取网页
                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("
    ","")
                        .replace("	","");
                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 {
        //数据库连接字符串,cc98为数据库名
        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驱动
            try
            {
                Class.forName("com.mysql.jdbc.Driver");
            }
            catch (ClassNotFoundException e)
            {
                System.out.println("未能成功加载驱动程序,请检查是否导入驱动程序!");
                e.printStackTrace();
            }
            try
            {
                conn = DriverManager.getConnection(URL, NAME, PASSWORD);
    //            System.out.println("获取数据库连接成功!");
            }
            catch (SQLException e)
            {
    //            System.out.println("获取数据库连接失败!");
                e.printStackTrace();
            }
        }
    
        public void close()
        {
            //关闭数据库
            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(?,?,?,?,?)";
                //使用预处理的方法
                PreparedStatement ps = null;
    
                ps = conn.prepareStatement(sql);
    
                //依次填入参数
                ps.setString(1,theme);
                java.sql.Time time = new java.sql.Time(publishTime.getTime());
                //这里使用数据库的时间戳
                ps.setTimestamp(2,new Timestamp(publishTime.getTime()));
                ps.setString(3,part);
                ps.setString(4,author);
                ps.setString(5,url);
    
                ps.executeUpdate();
            }
            catch (SQLException e)
            {
                //主要是重复的异常,在MySQL中已经有约束unique
    //            e.printStackTrace();
            }
        }
    }
    

    小结

    这个项目其实涉及的知识点还挺多的,博主也刚学java,很多细节也没有很好吃透,如JDBC、Jsoup都值得好好学习一下。欢迎大家批评指正。

    另,祝大家中秋国庆双节快乐~

  • 相关阅读:
    Java
    maven打包
    maven
    memset用法祥解
    HTML5 canvas save和restore方法讲解
    修复无线链接时断时连
    VirtualBox内Linux系统怎样与Windows共享文件夹
    Ubuntu默认密码,及其修改
    mysql中char与varchar的区别分析
    javax.servlet包介绍
  • 原文地址:https://www.cnblogs.com/fanghao/p/7629149.html
Copyright © 2011-2022 走看看