爬虫的综合案例

16 篇文章 0 订阅
5 篇文章 0 订阅

爬虫的综合案例爬取虎嗅网的完整Demo

创建Maven项目

  • 首先引入依赖
    <dependencies>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
        <dependency>
            <!-- jsoup HTML parser library @ https://jsoup.org/ -->
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.2.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.31</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.1</version>
        </dependency>

  </dependencies>

使用的是mysql数据库

  • 创建数据库名字为:spider

    create database spider;
    
  • 创建表的代码如下:

CREATE TABLE `huxiu_article` (
  `id` varchar(250) DEFAULT NULL,
  `title` varchar(250) DEFAULT NULL,
  `author` varchar(250) DEFAULT NULL,
  `createTime` varchar(250) DEFAULT NULL,
  `zan` varchar(250) DEFAULT NULL,
  `pl` varchar(250) DEFAULT NULL,
  `sc` varchar(250) DEFAULT NULL,
  `content` blob,
  `url` varchar(250) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

具体代码如下

实体类Article

public class Article {
    private String id;
    private String url;
    private String title;
    private String author;
    private String createTime;
    private String pl;
    private String zan;
    private String sc;
    private String content;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    ........

}

操作数据库的ArticleDao

public class ArticleDao extends JdbcTemplate {

    public ArticleDao() {
        // 创建C3P0的datasource 1.配置 2.代码
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 1.url
        // 2.driver
        // 3.username&password
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spider?characterEncoding=utf-8");
        setDataSource(dataSource);
    }

    public void save(Article article) {
        String sql = "INSERT INTO `spider`.`huxiu_article` (`id`, `title`, `author`, `createTime`, `zan`, `pl`, `sc`, `content`, `url` ) VALUES( ?,?,?,?,?,?,?,?,?)";
        update(sql, article.getId(),article.getTitle(),article.getAuthor(),article.getCreateTime(),article.getZan(),article.getPl(),article.getSc(),article.getContent(),article.getUrl());
    }
}

返回值的实体类HuxiuPagingResponse

    public class HuxiuPagingResponse {

    private String data;
    private String last_dateline;
    private String msg;
    private String result;
    private String total_page;
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
    ........

}

程序主方法入口HuXiuSpider

public class HuXiuSpider {
    // 保存数据
    public static ArticleDao articleDao = new ArticleDao();
    // dataLine用来做分页的请求
    private static String dateLine = null;
    // 创建固定大小的线程池(下载、解析、存储)
    private static ExecutorService threadPool = Executors.newFixedThreadPool(30);
    // 队列---从首页和分页解析出来的文章url,存放在这个队列中
    public static ArrayBlockingQueue<String> urlQueue = new ArrayBlockingQueue<String>(1000);
    // 队列---每个文章解析出来的Html文档,存放这个队列中
    public static ArrayBlockingQueue<String> articleHtmlQueue = new ArrayBlockingQueue<String>(1000);
    // 队列---每个文章的内容,也就是article对象,存放这个队列中
    public static ArrayBlockingQueue<Article> articleContentQueue = new ArrayBlockingQueue<Article>(1000);

    public static void main(String[] args) throws Exception {
        // 提交线程 用来针对每个文章的url ----进行网络请求
        for (int i = 0; i < 10; i++) {
            threadPool.execute(new ProcessSinglePageRunnable());
        }
        // 解析页面
        for (int i = 0; i < 10; i++) {
            threadPool.execute(new ParseHtmlRunnable());
        }
        // 保存数据
        threadPool.execute(new SaveDBRunnable());
        //获取首页的文章url列表
        getIndexArticleUrlList();
        //加载分页
        processPaging();
    }
    /**
     * 获取首页的文章列表信息
     * 
     * @throws IOException
     * @throws ClientProtocolException
     */
    private static void getIndexArticleUrlList() throws IOException, ClientProtocolException {
        // 1.指定首页url http://www.huxiu.com
        String indexUrl = "http://www.huxiu.com";
        // 2.发起一个HttpGet请求
        HttpGet indexHttpGet = new HttpGet(indexUrl);
        //设置User-Agent
        indexHttpGet.setHeader("User-Agent",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");

        String html = getHtmlByRequest(indexHttpGet);

        // 5.使用Jsoup进行解析,得到 文章的列表 ,获得文章aid。
        Document indexDocument = Jsoup.parse(html);

        // 获取date_line
        Elements dateLines = indexDocument.select("[data-last_dateline]");
        dateLine = dateLines.get(0).attr("data-last_dateline");

        // 5.1 解析出div的某个属性data-id
        Elements aidElements = indexDocument.select("div[data-aid]");
        // 5.2 依次得到每个新闻的aid
        for (Element element : aidElements) {
            String aid = element.attr("data-aid");
            try {
                urlQueue.put(aid);
            } catch (InterruptedException e) {
                System.out.println("添加 aid 到urlQueue异常" + e);
            }
        }
    }

    private static void processPaging() {
        for (int page = 2; page <= 1615; page++) {
            try {
                // 编写分页
                String pagingUrl = "https://www.huxiu.com/v2_action/article_list";
                HttpPost httpPost = new HttpPost(pagingUrl);
                // 设置参数
                ArrayList<NameValuePair> arrayList = new ArrayList<NameValuePair>();
                arrayList.add(new BasicNameValuePair("huxiu_hash_code", "fb7f7403c58c3e8cb45aa47afc204c10"));
                arrayList.add(new BasicNameValuePair("page", page + ""));
                arrayList.add(new BasicNameValuePair("last_dateline", dateLine));
                httpPost.setEntity(new UrlEncodedFormEntity(arrayList));
                // 执行网络参数
                String jsonText = getHtmlByRequest(httpPost);
                // 想将json串转成对象
                Gson gson = new Gson();
                HuxiuPagingResponse huxiuPagingResponse = gson.fromJson(jsonText, HuxiuPagingResponse.class);
                // 每一次请求,都需要解析出新的dataLine
                dateLine = huxiuPagingResponse.getLast_dateline();
                // 获取数据
                String htmlData = huxiuPagingResponse.getData();

                Document doc = Jsoup.parse(htmlData);
                // 解析出div的某个属性data-id
                Elements aidElements = doc.select("div[data-aid]");
                // 依次得到每个新闻的aid
                for (Element element : aidElements) {
                    String aid = element.attr("data-aid");
                    urlQueue.put(aid);
                }
            } catch (Exception e) {
                // log.errer()
                System.out.println(page);
                System.out.println(e);
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

    /**
     * 获取html文档
     * @throws IOException
     * @throws ClientProtocolException
     */
    public static String getHtml(String aidUrl) throws IOException, ClientProtocolException {
        // 2.发起一个httpget请求
        HttpGet indexHttpGet = new HttpGet(aidUrl);
        return getHtmlByRequest(indexHttpGet);
    }
    private static String getHtmlByRequest(HttpRequestBase request) throws IOException, ClientProtocolException {
        //设置请求头User-Agent
        request.setHeader("User-Agent",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");

        // 3.使用HttpClient执行,得到一个entity。
        CloseableHttpClient indexHttpClient = HttpClients.createDefault();
        CloseableHttpResponse indexResponse = indexHttpClient.execute(request);
        String html = null;
        if (200 == indexResponse.getStatusLine().getStatusCode()) {
            HttpEntity indexEntity = indexResponse.getEntity();
            // 4.将entity转成字符串(html)
            html = EntityUtils.toString(indexEntity, Charset.forName("utf-8"));
        }
        return html;
    }
}

用来针对每个文章的url 进行网络请求ProcessSinglePageRunnable

public class ProcessSinglePageRunnable  implements Runnable {

    public void run() {
        while (true) {
            try {
                processSingleUrl();
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
        }
    }

    private void processSingleUrl() throws InterruptedException {
        String aid = HuXiuSpider.urlQueue.take();
        String aidUrl = "http://www.huxiu.com/article/" + aid + ".html";
        try {
            /*Article article = new Article();
            article.setId(aid);*/
            // 获取到单个新闻页面的html
            String aidHtml = HuXiuSpider.getHtml(aidUrl);
            HuXiuSpider.articleHtmlQueue.put(aidHtml);
        } catch (Exception e) {
            System.out.println(aidUrl);
            System.out.println(e);
        }
    }
}

解析每个页面ParseHtmlRunnable

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class ParseHtmlRunnable implements Runnable {

    public void run() {
        while (true) {
            String html = null;
            try {
                html = HuXiuSpider.articleHtmlQueue.take();
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            Article article = new Article();
            Document detailDocument = Jsoup.parse(html);

            //解析出div的某个属性data-id
            Elements aidElements = detailDocument.select("div[data-aid]");
            String aid=aidElements.get(0).attr("data-aid");
            article.setId(aid);
            System.out.println(aid+".........");

            // 解析文章title
            Elements titles = detailDocument.select(".t-h1");
            String title = titles.get(0).text();
            article.setTitle(title);

            // 解析文章author author-name
            Elements names = detailDocument.select(".author-name");
            String name = names.get(0).text();
            article.setAuthor(name);
            // 解析文章发布时间
            Elements dates = detailDocument.select("[class^=article-time]");
            String date = dates.get(0).text();
            article.setCreateTime(date);
            // 解析文章 收藏数
            Elements shares = detailDocument.select("[class^=article-share]");
            String share = shares.get(0).text();
            article.setSc(share);
            // 解析文章 评论数
            Elements pls = detailDocument.select("[class^=article-pl]");
            String pl = pls.get(0).text();
            article.setPl(pl);
            // 解析文章 点赞数 num
            Elements nums = detailDocument.select(".num");
            String num = nums.get(0).text();
            article.setZan(num);
            // 解析文章正文内容 article-content-wrap
            Elements content = detailDocument.select(".article-content-wrap p");
            String contentText = content.text();
            article.setContent(contentText);
            // article.setUrl(aidUrl);
            try {
                HuXiuSpider.articleContentQueue.put(article);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

保存数据的类SaveDBRunnable

public class SaveDBRunnable implements Runnable {
    public void run() {
        while (true) {
            try {
                Article article = HuXiuSpider.articleContentQueue.take();
                HuXiuSpider.articleDao.save(article);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值