php多线程抓取多个网页(《爬虫/蜘蛛程序的制作(C#语言)》一文)

优采云 发布时间: 2021-10-12 14:25

  php多线程抓取多个网页(《爬虫/蜘蛛程序的制作(C#语言)》一文)

  在《爬虫/蜘蛛程序制作(C#语言)》一文中,已经介绍了爬虫程序的基本实现方法。可以说已经实现了爬虫的功能。只是有效率问题,下载速度可能会很慢。这是由两个原因造成的: 分析和下载不能同时进行。在《爬虫/蜘蛛程序制作(C#语言)》中,已经介绍了爬虫程序的两个步骤:分析和下载。在单线程程序中,两者不能同时执行。也就是说,分析时网络会处于空闲状态,分析时间越长,下载效率越低。反之亦然,下载时不能同时进行分析,并且只有在下载停止后才能进行下一步分析。问题浮出水面,我想大家会想:如果在不同的线程中进行分析和下载,问题是不是就解决了?这只是一个单线程下载。相信大家都有下载Flash Express等资源的经历。里面可以设置线程数(近几年默认是10个,默认是5)。它会把文件分成和线程数一样的部分,然后每个线程下载自己的自己的部分,这样下载效率可能会有所提高,相信大家都有增加线程数来提高下载效率的经验,但是细心的用户会发现,在一定带宽的情况下,并不是线程变得更有效率。越多,速度越快,而是某一点的峰值。爬虫作为一种特殊的下载工具,没有多线程能力怎么能高效呢?信息时代爬虫的目的不就是快速获取信息吗?所以,爬虫需要有多个线程(数量可控)同时下载网页。

  好了,理解和分析问题后,问题解决了:多线程在C#中实现并不难。它有一个命名空间:System.Threading,它提供多线程支持。要启动一个新线程,需要进行如下初始化: ThreadStart startDownload newThreadStart( DownLoad //线程启动设置:每个线程执行DownLoad(),注意:DownLoad() 必须是一个不带参数的方法 Thread downloadThread newThread( startDownload //实例化new class to be open downloadThread.Start();//启动线程,因为线程开头启动的方法不能带参数,给多线程共享资源增加了麻烦。但是我们可以使用类级别的变量(的当然也可以用其他方法,我觉得这个方法最简单好用)来解决这个问题。了解了启用多线程下载的方法后,大家可能会有几个疑问:如何控制线程的结束?这里提出几个问题来解决这个问题: 线程数可以通过一个for循环来实现,就像我们年初学编程时的dot程序一样。例如,已知用户指定了 n 个(它是一个 int 变量)线程。可以用下面的方法启动5个A线程Thread[]downloadThread;//信誉下载线程,这就是C#的优点,就是数组初始化的时候,不需要指定其长度,而且只能在使用时指定。如何控制线程的结束?这里提出几个问题来解决这个问题: 线程数可以通过一个for循环来实现,就像我们年初学编程时的dot程序一样。例如,已知用户指定了 n 个(它是一个 int 变量)线程。可以用下面的方法启动5个A线程Thread[]downloadThread;//信誉下载线程,这就是C#的优点,就是数组初始化的时候,不需要指定其长度,而且只能在使用时指定。如何控制线程的结束?这里提出几个问题来解决这个问题: 线程数可以通过一个for循环来实现,就像我们年初学编程时的dot程序一样。例如,已知用户指定了 n 个(它是一个 int 变量)线程。可以用下面的方法启动5个A线程Thread[]downloadThread;//信誉下载线程,这就是C#的优点,就是数组初始化的时候,不需要指定其长度,而且只能在使用时指定。

  这个声明应该是类级别的,这样就可以提供其他方法控件,可以 ThreadStartstartDownload newThreadStart(DownLoad);//线程启动设置:即每个线程执行DownLoad()downloadThreadnewThread[newThread(startDownload);//指定the thread start setting downloadThread[i].Start();//下面出现的一个问题,一一启动线程:所有线程都调用了DonwLoad()方法,那么如何防止它们同时下载同一个网页时间?这个问题也很容易解决,只需要创建一个Url地址表,表中的每个地址只允许一个线程申请。具体实现:可以使用数据库创建表。表中有四列。一列专用于存储 URL 地址。另外两列存储地址对应的线程和地址已经申请的次数。最后一列存储下载的内容。(当然,对应的线程列不是必须的)。有线程申请时,将对应的线程列设置为当前线程号,将是否申请某列设置为申请一次,其他线程无法申请该页面。如果下载成功,则将内容存储在内容列表中。如果不成功,则内容栏仍为空,作为是否重新下载的依据之一,如果反复不成功,则该过程将达到重试次数(对应地址已申请的次数,用户可以设置),申请下一个Url地址。

  主要代码如下(使用VFP CREATE TABLE (ctablename) &&创建表ctablename.dbf,收录地址、文本内容、下载尝试次数、线程标志(初始值-1,线程标志是从0) 四 字段 cfullname ´.dbf´&& 添加扩展名 USE (cfullname) GO TOP LOCATE (EMPTY(ALLTRIM( ctext &&) ) 未成功下载的表应下载到属于权限的 Url 地址这个线程的,thisNum是当前线程的编号,可以通过参数获取gotUrl curlrecNum && 如果在列表中找到这样的Url地址 UPDATE (cfullname) SET ldowned thisNumWHERE RECNO() recNum&& 更新表,更新这条记录被请求,即下载次数增加1,并且线程标志列设置为 编译该线程的cfulltablename ´.dbf´USE (cfulltablename) SET EXACT (csiteurl)&&csiteurl 为参数,即下载内容对应的URL地址 recNumNow RECNO()&& 得到收录这个地址的记录号 UPDATE (cfulltablename) SET ctext (ccontent)WHERE RECNO() recNumNow&&插入对应地址的对应内容 ctablename ´.dbf´USE (ctablename) GO TOP SET EXACT (cnewurl)&&查找是否有这个地址&&如果有还没有这个地址 SET CARRY OFF INSERT &&设置主页地址 加入列表,解决多线程中的线程冲突。csiteurl为参数,为下载内容对应的URL地址 recNumNow RECNO()&&获取收录该地址的记录号 UPDATE (cfulltablename) SET ctext (ccontent)WHERE RECNO() recNumNow&&插入对应地址的对应内容 ctablename ´.dbf´USE (ctablename) GO TOP SET EXACT (cnewurl)&&查找是否有这个地址&&如果还没有这个地址 SET CARRY OFF INSERT &&设置主页地址 添加到列表中,这样多线程中的线程冲突是解决。csiteurl为参数,为下载内容对应的URL地址 recNumNow RECNO()&&获取收录该地址的记录号 UPDATE (cfulltablename) SET ctext (ccontent)WHERE RECNO() recNumNow&&插入对应地址的对应内容 ctablename ´.dbf´USE (ctablename) GO TOP SET EXACT (cnewurl)&&查找是否有这个地址&&如果还没有这个地址 SET CARRY OFF INSERT &&设置主页地址 添加到列表中,这样多线程中的线程冲突是解决。插入对应地址的对应内容 ctablename ´.dbf´USE (ctablename) GO TOP SET EXACT (cnewurl)&&查找是否有这个地址&&如果还没有这个地址 SET CARRY OFF INSERT &&设置主页地址 加入列表,所以解决了多线程中的线程冲突。插入对应地址的对应内容 ctablename ´.dbf´USE (ctablename) GO TOP SET EXACT (cnewurl)&&查找是否有这个地址&&如果还没有这个地址 SET CARRY OFF INSERT &&设置主页地址 加入列表,所以解决了多线程中的线程冲突。

  当然,去重的问题也可以用C#语言解决,只需要创建一个临时文件(文本就够了),保存所有的Url地址,并为它们设置相应的属性,但是搜索效率可能没有那么快数据库。第二次后,仍然无法申请新的URL地址,则可以认为已经下载了所有链接。主要代码如下: string url inttimes );//调用GetAUrl方法尝试获取一个url times++;//尝试次数递增continue; //进行下一次尝试downloadThread[i].Abort;//退出进程//Continue 一步处理获取到的Url比较简单,因为在第一个问题中已经提示该线程称为a类级数组,非常容易控制。只需使用 for 循环结束。代码如下:)//关闭指定数量的线程n,一个蜘蛛程序就这样完成了,在C#面前,它的实现竟然如此简单。在这里我也想提醒读者:我只提供了一个想法和一个可实现的解决方案,但并不是最好的。即便是解决方案本身,也有很多可以改进的地方,留给读者去思考。最后说明一下我使用的环境:winXP sp2 Pro VFP 9.0 Visual Studio 2003 .net 中文企业版 可以改进的地方很多,留给读者去思考。最后说明一下我使用的环境:winXP sp2 Pro VFP 9.0 Visual Studio 2003 .net 中文企业版 可以改进的地方很多,留给读者去思考。最后说明一下我使用的环境:winXP sp2 Pro VFP 9.0 Visual Studio 2003 .net 中文企业版

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线