Java爬虫(一)

一、基本流程

1. 获取链接列表

2. 判断链接是否重复,并解析网页

3. 将数据写入数据库

4. 多线程并发执行

二、具体步骤

1. 获取链接列表

这一步比较简单,只需了解待爬网页特性即可,并把正确的链接等数据放入redis列表即可

//获取页面中文章网址等相关信息,并存入队列中
            int start = html.indexOf(":[{") + ":[".length();
            html = html.substring(start);
            int end = html.indexOf("}]")+1;
            //
            if(end>0){
                html = html.substring(0, end);
                //System.out.println(html);
                //用于检测字符串是否以指定的前缀开始
                String str_html=html;
                //System.out.println(html.length());
                int str_end=0;
                boolean flag=true;

                while(flag&&str_html.length()>0&&str_html.startsWith("{")){
                    String s_html=null;
                    str_end=str_html.indexOf("}")+2;
                    if(str_end<str_html.length()){
                        s_html=str_html.substring(0, str_end-1);
                        str_html=str_html.substring(str_end);
                    }
                    else{
                        flag=false;
                        s_html=str_html;
                    }


                    if(html.startsWith("{"))
                    {
                        JSONObject info=JSONObject.fromObject(s_html);
                        //System.out.println(info.toString());
                        info.put("local3",cid_name);
                        //System.out.println(info.toString().getBytes());
                        ju.lpush(redisKey_wemedia, info.toString().getBytes());
                    }

                }
            }

这里写图片描述

2. 判断链接是否重复,并解析网页

这里用到了布隆筛选器,不过不是我自己写的代码。通过某一键的多个哈希值来判断该键是否存在,若有一个哈希结果显示该键不存在,则这个键一定不存在,但反之不一定。通过这个筛选器判断出一条链接信息是否需要加入数据库队列中

3. 将数据写入数据库

从数据库队列中拿出链接数据,解析链接下的网页,并写入数据库中,或者其他地方。

    //解析url,获取正文
    public String getContent(String url){
        String content=null;
        ArrayList<header> list=new ArrayList<header>();
        header h=new header("User-Agent","Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Mobile Safari/537.36");
        list.add(new header("Host","html2.qktoutiao.com"));
        //list.add(new header("Connection","keep-alive"));
        list.add(h);
        String html=pageDown.Pageinfo(url, list,"utf-8");
//      System.out.println(url);
//      System.out.println(html);
        Document doc=Jsoup.parse(html,url);
        Elements es=doc.getElementsByTag("p");
        content= es.text();
        return content;
    }

注意的是最好保证从网页中获取的数据都不是空的,特别是正文和标题

4. 多线程并发执行

设置多个线程并发执行,要注意隔一段时间监测是否有线程挂掉了,对于挂了的重新new一个

        //任务调度
        ArrayList<Thread> allThreadsListSd = new ArrayList<Thread>();
        ArrayList<CrawlSysScheduler> allSimpleCrawlerListSd = new ArrayList<CrawlSysScheduler>();
        for (int i = 0; i < slaveNumSd; i++) {
            CrawlSysScheduler tmpSimpleCrawler = new CrawlSysScheduler();
            allSimpleCrawlerListSd.add(tmpSimpleCrawler);
            allThreadsListSd.add(new Thread(tmpSimpleCrawler));
        }
        for (int i = 0; i < slaveNumSd; i++) {
            allThreadsListSd.get(i).start();
        }

        //写入数据库
        ArrayList<Thread> allThreadsListDB = new ArrayList<Thread>();
        ArrayList<DBtask> allSimpleDBList = new ArrayList<DBtask>();
        for (int i = 0; i < slaveNumDB; i++) {
            DBtask tmpSimpleCrawler = new DBtask();
            allSimpleDBList.add(tmpSimpleCrawler);
            allThreadsListDB.add(new Thread(tmpSimpleCrawler));
        }
        for (int i = 0; i < slaveNumDB; i++) {
            allThreadsListDB.get(i).start();
        }

        while (true) {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (Exception e) {
                e.printStackTrace();
            }

            for (int i = 0; i < slaveNumSd; i++) {
                if (!allThreadsListSd.get(i).isAlive()) {
                    System.out.println("allThreadsListSd"+i);
                    allThreadsListSd.remove(i);
                    allSimpleCrawlerListSd.remove(i);
                    CrawlSysScheduler tmpSimpleCrawler = new CrawlSysScheduler();
                    allSimpleCrawlerListSd.add(i, tmpSimpleCrawler);
                    Thread tmpThread = new Thread(tmpSimpleCrawler);
                    tmpThread.start();
                    allThreadsListSd.add(i, tmpThread);
                }
            }

            for (int i = 0; i < slaveNumDB; i++) {
                if (!allThreadsListDB.get(i).isAlive()) {
                    System.out.println("allThreadsListDB"+i);
                    allThreadsListDB.remove(i);
                    allSimpleDBList.remove(i);
                    DBtask tmpSimpleCrawler = new DBtask();
                    allSimpleDBList.add(i, tmpSimpleCrawler);
                    Thread tmpThread = new Thread(tmpSimpleCrawler);
                    tmpThread.start();
                    allThreadsListDB.add(i, tmpThread);
                }
            }
        }

我这只写了两种任务线程,其中1为单独一个,2.3合并在一起为一个,后期优化时可以适当分工,加快处理速度

猜你喜欢

转载自blog.csdn.net/qq_20366761/article/details/81569053