问答系统--站内爬虫

本文讲述了作者在课题需求下,选择自建爬虫而非使用webmagic框架的过程。主要涉及如何维护爬虫队列、选择合适的Java集合、使用jsoup解析HTML、正则表达式去噪以及文件操作。通过实现这个爬虫,作者强调了异常处理、集合特性理解、IO操作和多线程在爬虫开发中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:
由于课题需要,我需要爬取特定网站的 一批领域页面,从而来提取领域词

可选做法:
1 使用java的爬虫框架 webmagic。
2 自己写爬虫

评价:
使用webmagic框架:好处是,我不需要自己去维护管理 爬虫队列。这是件很烦躁的事情。只需要自己在processor中,设定自己对页面的提取要求。 不好处是,processor里面一般使用的是 正则表达式,或者xpath来提取网页想要的内容。而我喜欢用jsoup

我的方案:
自己去写一个爬虫。需要涉及到很多东西。
A)其中,一开始最大的难题是 如何维护,管理2个爬虫队列(已爬取url集合W1,待爬取url集合W2

B)java自带的集合的选择

C)jsoup的使用

D) 正则表达式去除噪声

E)输入输出文件的操作

一开始,我的想法过于复杂。我想的是 增量访问url集合。1)希望 已爬取URl集合里面不可以有重复的。2)待爬取url集合里面也没有重复的url。 3)每次扩张 待爬取Url集合W2的时候,集合容量的问题,还有每条扩张的url都不能是历史访问过的。 想的太复杂

最终的做法就是:
A)
private static LinkedList visitedUrlQueue = new
LinkedList();
private static LinkedHashSet urlQueue = new
LinkedHashSet();

每次从urlQueue中取出一个url,然后到visitedUrlQueue去判断是否存在,然后访问url对应的页面page1后,提取page1中的所有链接,直接加入urlQueue中。然后判断把该url添加进visitedUrlQueue。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
所以说,爬虫框架如果熟悉的话,确实可以帮助 减少很多工作量。在你都不怎么懂内部运行效率和原理的时候,帮你完成一个爬虫。
比如:爬虫队列如何 维护
比如:网络操作,如何进行请求和解析。如何,进行反爬
但是,总得对我来说,目前框架最重要的是可以帮忙管理爬虫队列。

B)
集合Queue,感觉好难用
集合List,感觉,就是个容器,不能保证唯一性,更不能保证插入到顺序
集合map,是可以控制 唯一性
集合linked,是意思 可以保持 插入的顺序
集合Set, 可以控制 唯一性,而且,只是有个key而已,没有value字段
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如何保证唯一性,还能保证每次都能按指定位置访问?
目前好像还没有这种集合。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
针对上述需求,这次我的处理:
是采用map+iterator+每次判断hasnext(),然后访问头一个元素后,remove头一个元素。
总结:list集合可以按 index,直接取值。而map,set类的,要么按key访问,要么按照iterator,从头到尾进行遍历访问。所以说,Iterator对于map,set集合,是必须得要的。而对于list集合,则不是那么需要。

重要code:

while(s.urlQueue.size()!=0)
        {  
            String url="";
            Iterator it = s.urlQueue.iterator();
            if(it.hasNext())
               {
                 url=  it.next().toString();
                 s.urlQueue.remove(url);
               }

C)
jsoup的使用,确实很简单,好用。如下,提取html中的所有url.
:
Document doc = Jsoup.parse(s);
Elements links = doc.getElementsByTag(“a”);
links.getElementsByTag(“href”);
for (Element link : links)
{ String linkHref = link.attr(“href”);

 }

D)
去噪:
正则表达式很常用。
//去除非数字,字母,汉字的字符
1 sss.replaceAll(“[^\u4e00-\u9fa5。,,]”,” “);
2 sss.replaceAll(“[^\u4e00-\u9fa5a-zA-Z0-9。,,]”,” “);
//去除url的前后引号
3 String temp=url.replaceAll(“[^a-zA-Z0-9]”,”“);

String temp= sss.replaceAll(“[^\u4e00-\u9fa5。,,]”,” “);
System.out.println(temp);

E)
1 获得一个文件夹下的 所有文件
2 写入文件

public static ArrayList<File> getListFiles(Object obj) {  
            File directory = null;  
            if (obj instanceof File) {  
                directory = (File) obj;  
            } else {  
                directory = new File(obj.toString());  
            }  
            ArrayList<File> files = new ArrayList<File>();  
            if (directory.isFile()) {  
                files.add(directory);  
                return files;  
            } else if (directory.isDirectory()) {  
                File[] fileArr = directory.listFiles();  
                for (int i = 0; i < fileArr.length; i++) {  
                    File fileOne = fileArr[i];  
                    files.addAll(getListFiles(fileOne));  
                }  
            }  
            return files;  
        }  


public void saveFile(String fileName,String content) throws IOException
    {
        File file =new File(fileName);
        if(!file.exists())
        {       
            System.out.println("不存在");
            System.out.println(file.createNewFile());
            file.createNewFile();
        }


            FileOutputStream fos = new FileOutputStream(file,false);
            OutputStreamWriter out =new OutputStreamWriter(fos,"utf-8");
            BufferedWriter bw = new BufferedWriter(out);
            bw.write(content);
            bw.write("\r\n");
            bw.flush();
            System.out.println("创建成功");

    }


3 读取文件

public void solve(String filepath,int index) throws IOException
     {
         FileReader fr=new FileReader(filepath);
            //可以换成工程目录下的其他文本文件
            //String temp="";
            StringBuilder build=new StringBuilder();
            BufferedReader br=new BufferedReader(fr);
            while(br.readLine()!=null){
                String ss=br.readLine();
                build.append(ss);
                //System.out.println(ss);
            }
            br.close();
            String sss=build.toString();

           String temp= sss.replaceAll("[^\u4e00-\u9fa5。,,]"," ");
            System.out.println(temp);
            saveFile("D:\\素食2\\"+index+".txt",temp);

            System.out.println(index);

     }

F)
static 变量的重要性。这一次处理 如何维护爬虫队列,就是依靠static关键字。

G)
java提供的异常处理的作用,太棒了。本来只可以爬取1500多页就报错了,后来使用异常处理后,直接 爬取了32956页。
code:

try {
                    list_temp=s.fetch(url.replace("\"", ""));
                } catch (IOException e) {
                    // TODO Auto-generated catch block

                }
              catch(IllegalArgumentException e2)
                {
                    list_temp=null;
                }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
总结:
这个小程序又巩固了 java基础的很多东西
1 异常处理的作用,太棒了,使得程序不会就那么停住了
2 集合之所以含有那么多 类,是因为每个类有自己的特性,要按照需求来选择。对于map/set这两类集合,离开了迭代器iterator,寸步难行啊。哈哈。 重要的是,要牢牢的 记清楚,每个类都有哪些特性啊。这样使用的时候,才选择的快一些。

3 文件的输入输出IO操作,反反复复就那么几段话,自己只要搞懂这几段,一定要写熟练。
NIO操作,还是不会。

4 String的+符号,虽然很好用。不过要尽量改成 StringBuilder,效率差的太多了

5 要使用多线程,来提高爬取的速度啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值