Ⅰ 为什么c语言不适合写爬虫
c语言不适合写爬虫是因为,C语言本质上是需要发请求加html解析的,所以可用的开源库相比较于Python来说就会少很多,如果不使用开源库而自己发请求,加上自己来解析,那就是一个特别浩瀚庞大的工程,因此最好不要用c语言来写爬虫。这里所说的爬虫,其实原理了来说就是发送HTTP请求加上解析html页面,从而能够获取页面上的一些目标数据。任何的一个编程语言理论上来说都是能够写爬虫的,不过写起来可用的库或者是难易程度方面是有很大的差异的,用python可以使用别人已经封装好的爬虫框架,这样就便捷多了。
C语言和 Python 是编程语言界的两个极端,从不同的语言入手学习,就是选择了两条不同的学习路径。C语言执行效率极高,堪比汇编语言;Python 执行效率极低,而且没法提速。Python 模块非常丰富,大部分常用功能都可以找到对应的模块,而且很有可能不止一个;C语言基本没有什么模块,想要什么都得自己开发,或者把别人写好的代码拿过来改改。
![](http://www.gotrillian.com/images/loading.jpg)
Ⅱ python为什么叫爬虫
因为python的脚本特性,易于配置,对字符的处理也非常灵活,就像虫子一样灵活,故名爬虫。
Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载、派生、多继承,有益于增强源代码的复用性。
Python支持重载运算符和动态类型。相对于Lisp这种传统的函数式编程语言,Python对函数式设计只提供了有限的支持。有两个标准库(functools, itertools)提供了Haskell和Standard ML中久经考验的函数式程序设计工具。
扩展资料
Python的设计目标之一是让代码具备高度的可阅读性。它设计时尽量使用其它语言经常使用的标点符号和英文单字,让代码看起来整洁美观。它不像其他的静态语言如C、Pascal那样需要重复书写声明语句,也不像它们的语法那样经常有特殊情况和意外。
Python开发者有意让违反了缩进规则的程序不能通过编译,以此来强制程序员养成良好的编程习惯。
并且Python语言利用缩进表示语句块的开始和退出(Off-side规则),而非使用花括号或者某种关键字。增加缩进表示语句块的开始,而减少缩进则表示语句块的退出。缩进成为了语法的一部分。
例如if语句:python3。
Ⅲ C#爬虫爬虫的多线程如何实现
开发网络爬虫应该选择Nutch、Crawler4j、WebMagic、scrapy、WebCollector还是其他的?这里按照我的经验随便扯淡一下:上面说的爬虫,基本可以分3类:1.分布式爬虫:Nutch
2.JAVA单机爬虫:Crawler4j、WebMagic、WebCollector
3. 非JAVA单机爬虫:scrapy
第一类:分布式爬虫
爬虫使用分布式,主要是解决两个问题:
1)海量URL管理
2)网速
现在比较流行的分布式爬虫,是Apache的Nutch。但是对于大多数用户来说,Nutch是这几类爬虫里,最不好的选择,理由如下:
1)Nutch是为搜索引擎设计的爬虫,大多数用户是需要一个做精准数据爬取(精抽取)的爬虫。Nutch运行的一套流程里,有三分之二是为了搜索引擎而设计的。对精抽取没有太大的意义。也就是说,用Nutch做数据抽取,会浪费很多的时间在不必要的计算上。而且如果你试图通过对Nutch进行二次开发,来使得它适用于精抽取的业务,基本上就要破坏Nutch的框架,把Nutch改的面目全非,有修改Nutch的能力,真的不如自己重新写一个分布式爬虫框架了。
2)Nutch依赖hadoop运行,hadoop本身会消耗很多的时间。如果集群机器数量较少,爬取速度反而不如单机爬虫快。
3)Nutch虽然有一套插件机制,而且作为亮点宣传。可以看到一些开源的Nutch插件,提供精抽取的功能。但是开发过Nutch插件的人都知道,Nutch的插件系统有多蹩脚。利用反射的机制来加载和调用插件,使得程序的编写和调试都变得异常困难,更别说在上面开发一套复杂的精抽取系统了。而且Nutch并没有为精抽取提供相应的插件挂载点。Nutch的插件有只有五六个挂载点,而这五六个挂载点都是为了搜索引擎服务的,并没有为精抽取提供挂载点。大多数Nutch的精抽取插件,都是挂载在“页面解析”(parser)这个挂载点的,这个挂载点其实是为了解析链接(为后续爬取提供URL),以及为搜索引擎提供一些易抽取的网页信息(网页的meta信息、text文本)。
4)用Nutch进行爬虫的二次开发,爬虫的编写和调试所需的时间,往往是单机爬虫所需的十倍时间不止。了解Nutch源码的学习成本很高,何况是要让一个团队的人都读懂Nutch源码。调试过程中会出现除程序本身之外的各种问题(hadoop的问题、hbase的问题)。
5)很多人说Nutch2有gora,可以持久化数据到avro文件、hbase、mysql等。很多人其实理解错了,这里说的持久化数据,是指将URL信息(URL管理所需要的数据)存放到avro、hbase、mysql。并不是你要抽取的结构化数据。其实对大多数人来说,URL信息存在哪里无所谓。
6)Nutch2的版本目前并不适合开发。官方现在稳定的Nutch版本是nutch2.2.1,但是这个版本绑定了gora-0.3。如果想用hbase配合nutch(大多数人用nutch2就是为了用hbase),只能使用0.90版本左右的hbase,相应的就要将hadoop版本降到hadoop 0.2左右。而且nutch2的官方教程比较有误导作用,Nutch2的教程有两个,分别是Nutch1.x和Nutch2.x,这个Nutch2.x官网上写的是可以支持到hbase 0.94。但是实际上,这个Nutch2.x的意思是Nutch2.3之前、Nutch2.2.1之后的一个版本,这个版本在官方的SVN中不断更新。而且非常不稳定(一直在修改)。
所以,如果你不是要做搜索引擎,尽量不要选择Nutch作为爬虫。有些团队就喜欢跟风,非要选择Nutch来开发精抽取的爬虫,其实是冲着Nutch的名气(Nutch作者是Doug Cutting),当然最后的结果往往是项目延期完成。
如果你是要做搜索引擎,Nutch1.x是一个非常好的选择。Nutch1.x和solr或者es配合,就可以构成一套非常强大的搜索引擎了。如果非要用Nutch2的话,建议等到Nutch2.3发布再看。目前的Nutch2是一个非常不稳定的版本。
第二类:JAVA单机爬虫
这里把JAVA爬虫单独分为一类,是因为JAVA在网络爬虫这块的生态圈是非常完善的。相关的资料也是最全的。这里可能有争议,我只是随便扯淡。
其实开源网络爬虫(框架)的开发非常简单,难问题和复杂的问题都被以前的人解决了(比如DOM树解析和定位、字符集检测、海量URL去重),可以说是毫无技术含量。包括Nutch,其实Nutch的技术难点是开发hadoop,本身代码非常简单。网络爬虫从某种意义来说,类似遍历本机的文件,查找文件中的信息。没有任何难度可言。之所以选择开源爬虫框架,就是为了省事。比如爬虫的URL管理、线程池之类的模块,谁都能做,但是要做稳定也是需要一段时间的调试和修改的。
对于爬虫的功能来说。用户比较关心的问题往往是:
1)爬虫支持多线程么、爬虫能用代理么、爬虫会爬取重复数据么、爬虫能爬取JS生成的信息么?
不支持多线程、不支持代理、不能过滤重复URL的,那都不叫开源爬虫,那叫循环执行http请求。
能不能爬js生成的信息和爬虫本身没有太大关系。爬虫主要是负责遍历网站和下载页面。爬js生成的信息和网页信息抽取模块有关,往往需要通过模拟浏览器(htmlunit,selenium)来完成。这些模拟浏览器,往往需要耗费很多的时间来处理一个页面。所以一种策略就是,使用这些爬虫来遍历网站,遇到需要解析的页面,就将网页的相关信息提交给模拟浏览器,来完成JS生成信息的抽取。
2)爬虫可以爬取ajax信息么?
网页上有一些异步加载的数据,爬取这些数据有两种方法:使用模拟浏览器(问题1中描述过了),或者分析ajax的http请求,自己生成ajax请求的url,获取返回的数据。如果是自己生成ajax请求,使用开源爬虫的意义在哪里?其实是要用开源爬虫的线程池和URL管理功能(比如断点爬取)。
如果我已经可以生成我所需要的ajax请求(列表),如何用这些爬虫来对这些请求进行爬取?
爬虫往往都是设计成广度遍历或者深度遍历的模式,去遍历静态或者动态页面。爬取ajax信息属于deep web(深网)的范畴,虽然大多数爬虫都不直接支持。但是也可以通过一些方法来完成。比如WebCollector使用广度遍历来遍历网站。爬虫的第一轮爬取就是爬取种子集合(seeds)中的所有url。简单来说,就是将生成的ajax请求作为种子,放入爬虫。用爬虫对这些种子,进行深度为1的广度遍历(默认就是广度遍历)。
3)爬虫怎么爬取要登陆的网站?
这些开源爬虫都支持在爬取时指定cookies,模拟登陆主要是靠cookies。至于cookies怎么获取,不是爬虫管的事情。你可以手动获取、用http请求模拟登陆或者用模拟浏览器自动登陆获取cookie。
4)爬虫怎么抽取网页的信息?
开源爬虫一般都会集成网页抽取工具。主要支持两种规范:CSS SELECTOR和XPATH。至于哪个好,这里不评价。
5)爬虫怎么保存网页的信息?
有一些爬虫,自带一个模块负责持久化。比如webmagic,有一个模块叫pipeline。通过简单地配置,可以将爬虫抽取到的信息,持久化到文件、数据库等。还有一些爬虫,并没有直接给用户提供数据持久化的模块。比如crawler4j和webcollector。让用户自己在网页处理模块中添加提交数据库的操作。至于使用pipeline这种模块好不好,就和操作数据库使用ORM好不好这个问题类似,取决于你的业务。
6)爬虫被网站封了怎么办?
爬虫被网站封了,一般用多代理(随机代理)就可以解决。但是这些开源爬虫一般没有直接支持随机代理的切换。所以用户往往都需要自己将获取的代理,放到一个全局数组中,自己写一个代理随机获取(从数组中)的代码。
7)网页可以调用爬虫么?
爬虫的调用是在Web的服务端调用的,平时怎么用就怎么用,这些爬虫都可以使用。
8)爬虫速度怎么样?
单机开源爬虫的速度,基本都可以讲本机的网速用到极限。爬虫的速度慢,往往是因为用户把线程数开少了、网速慢,或者在数据持久化时,和数据库的交互速度慢。而这些东西,往往都是用户的机器和二次开发的代码决定的。这些开源爬虫的速度,都很可以。
9)明明代码写对了,爬不到数据,是不是爬虫有问题,换个爬虫能解决么?
如果代码写对了,又爬不到数据,换其他爬虫也是一样爬不到。遇到这种情况,要么是网站把你封了,要么是你爬的数据是javascript生成的。爬不到数据通过换爬虫是不能解决的。
10)哪个爬虫可以判断网站是否爬完、那个爬虫可以根据主题进行爬取?
爬虫无法判断网站是否爬完,只能尽可能覆盖。
至于根据主题爬取,爬虫之后把内容爬下来才知道是什么主题。所以一般都是整个爬下来,然后再去筛选内容。如果嫌爬的太泛,可以通过限制URL正则等方式,来缩小一下范围。
11)哪个爬虫的设计模式和构架比较好?
设计模式纯属扯淡。说软件设计模式好的,都是软件开发完,然后总结出几个设计模式。设计模式对软件开发没有指导性作用。用设计模式来设计爬虫,只会使得爬虫的设计更加臃肿。
至于构架,开源爬虫目前主要是细节的数据结构的设计,比如爬取线程池、任务队列,这些大家都能控制好。爬虫的业务太简单,谈不上什么构架。
所以对于JAVA开源爬虫,我觉得,随便找一个用的顺手的就可以。如果业务复杂,拿哪个爬虫来,都是要经过复杂的二次开发,才可以满足需求。
第三类:非JAVA单机爬虫
在非JAVA语言编写的爬虫中,有很多优秀的爬虫。这里单独提取出来作为一类,并不是针对爬虫本身的质量进行讨论,而是针对larbin、scrapy这类爬虫,对开发成本的影响。
先说python爬虫,python可以用30行代码,完成JAVA 50行代码干的任务。python写代码的确快,但是在调试代码的阶段,python代码的调试往往会耗费远远多于编码阶段省下的时间。使用python开发,要保证程序的正确性和稳定性,就需要写更多的测试模块。当然如果爬取规模不大、爬取业务不复杂,使用scrapy这种爬虫也是蛮不错的,可以轻松完成爬取任务。
对于C++爬虫来说,学习成本会比较大。而且不能只计算一个人的学习成本,如果软件需要团队开发或者交接,那就是很多人的学习成本了。软件的调试也不是那么容易。
还有一些ruby、php的爬虫,这里不多评价。的确有一些非常小型的数据采集任务,用ruby或者php很方便。但是选择这些语言的开源爬虫,一方面要调研一下相关的生态圈,还有就是,这些开源爬虫可能会出一些你搜不到的BUG(用的人少、资料也少)
Ⅳ 我想学习网络爬虫,哪位高手能给我发代码java、c#、C++都可以,先谢谢了。邮箱:[email protected]
C#特别适合于构造蜘蛛程序,这是因为它已经内置了HTTP和多线程的能力,而这两种能力对于蜘蛛程序来说都是非常关键的。下面是构造一个蜘蛛程序要解决的关键问题:⑴ HTML分析:需要某种HTML解析器来分析蜘蛛程序遇到的每一个页面。
⑵ 页面处理:需要处理每一个下载得到的页面。下载得到的内容可能要保存到磁盘,或者进一步分析处理。
⑶ 多线程:只有拥有多线程能力,蜘蛛程序才能真正做到高效。
⑷ 确定何时完成:不要小看这个问题,确定任务是否已经完成并不简单,尤其是在多线程环境下。
一、HTML解析
提供的HTML解析器由ParseHTML类实现,使用非常方便:首先创建该类的一个实例,然后将它的Source属性设置为要解析的HTML文档:
以下是代码片段:
ParseHTMLparse=newParseHTML();
parse.Source="HelloWorld";
接下来就可以利用循环来检查HTML文档包含的所有文本和标记。通常,检查过程可以从一个测试Eof方法的while循环开始:
以下是代码片段:
while(!parse.Eof())
{
charch=parse.Parse();
Parse方法将返回HTML文档包含的字符它返回的内容只包含那些非HTML标记的字符,如果遇到了HTML标记,Parse方法将返回0值,表示现在遇到了一个HTML标记。遇到一个标记之后,我们可以用GetTag()方法来处理它。
以下是代码片段:
if(ch==0)
{
HTMLTagtag=parse.GetTag();
}
一般地,蜘蛛程序最重要的任务之一就是找出各个HREF属性,这可以借助C#的索引功能完成。例如,下面的代码将提取出HREF属性的值(如果存在的话)。
以下是代码片段:
Attributehref=tag["HREF"];
stringlink=href.Value;
获得Attribute对象之后,通过Attribute.Value可以得到该属性的值。
二、处理HTML页面
下面来看看如何处理HTML页面。首先要做的当然是下载HTML页面,这可以通过C#提供的HttpWebRequest类实现:
以下是代码片段:
HttpWebRequestrequest=(HttpWebRequest)WebRequest.Create(m_uri);
response=request.GetResponse();
stream=response.GetResponseStream();
接下来我们就从request创建一个stream流。在执行其他处理之前,我们要先确定该文件是二进制文件还是文本文件,不同的文件类型处理方式也不同。下面的代码确定该文件是否为二进制文件。
以下是代码片段:
if(!response.ContentType.ToLower().StartsWith("text/"))
{
SaveBinaryFile(response);
returnnull;
}
stringbuffer="",line;
如果该文件不是文本文件,我们将它作为二进制文件读入。如果是文本文件,首先从stream创建一个StreamReader,然后将文本文件的内容一行一行加入缓冲区。
以下是代码片段:
reader=newStreamReader(stream);
while((line=reader.ReadLine())!=null)
{
buffer+=line+"rn";
}
装入整个文件之后,接着就要把它保存为文本文件。
以下是代码片段:
SaveTextFile(buffer);
下面来看看这两类不同文件的存储方式。
二进制文件的内容类型声明不以"text/"开头,蜘蛛程序直接把二进制文件保存到磁盘,不必进行额外的处理,这是因为二进制文件不包含HTML,因此也不会再有需要蜘蛛程序处理的HTML。下面是写入二进制文件的步骤。
首先准备一个缓冲区临时地保存二进制文件的内容。
以下是代码片段:
byte[]buffer=newbyte[1024];
接下来要确定文件保存到本地的路径和名称。如果要把一个myhost.com网站的内容下载到本地的c:test文件夹,二进制文件的网上路径和名称是,则本地路径和名称应当是c:testimageslogo.gif。与此同时,我们还要确保c:test目录下已经创建了images子目录。这部分任务由convertFilename方法完成。
以下是代码片段:
stringfilename=convertFilename(response.ResponseUri);
convertFilename方法分离HTTP地址,创建相应的目录结构。确定了输出文件的名字和路径之后就可以打开读取Web页面的输入流、写入本地文件的输出流。
以下是代码片段:
StreamoutStream=File.Create(filename);
StreaminStream=response.GetResponseStream();
接下来就可以读取Web文件的内容并写入到本地文件,这可以通过一个循环方便地完成。
以下是代码片段:
intl;
do
{
l=inStream.Read(buffer,0,
buffer.Length);
if(l>0)
outStream.Write(buffer,0,l);
}
while(l>0);
三、多线程
我们用DocumentWorker类封装所有下载一个URL的操作。每当一个DocumentWorker的实例被创建,它就进入循环,等待下一个要处理的URL。下面是DocumentWorker的主循环:
以下是代码片段:
while(!m_spider.Quit)
{
m_uri=m_spider.ObtainWork();
m_spider.SpiderDone.WorkerBegin();
stringpage=GetPage();
if(page!=null)
ProcessPage(page);
m_spider.SpiderDone.WorkerEnd();
}
这个循环将一直运行,直至Quit标记被设置成了true(当用户"Cancel"按钮时,Quit标记就被设置成true)。在循环之内,我们调用ObtainWork获取一个URL。ObtainWork将一直等待,直到有一个URL可用这要由其他线程解析文档并寻找才能获得。Done类利用WorkerBegin和WorkerEnd方法来确定何时整个下载操作已经完成。
从图一可以看出,蜘蛛程序允许用户自己确定要使用的线程数量。在实践中,线程的最佳数量受许多因素影响。如果你的机器性能较高,或者有两个处理器,可以设置较多的线程数量;反之,如果网络带宽、机器性能有限,设置太多的线程数量其实不一定能够提高性能。
四、任务完成了吗?
利用多个线程同时下载文件有效地提高了性能,但也带来了线程管理方面的问题。其中最复杂的一个问题是:蜘蛛程序何时才算完成了工作?在这里我们要借助一个专用的类Done来判断。
首先有必要说明一下"完成工作"的具体含义。只有当系统中不存在等待下载的URL,而且所有工作线程都已经结束其处理工作时,蜘蛛程序的工作才算完成。也就是说,完成工作意味着已经没有等待下载和正在下载的URL。
Done类提供了一个WaitDone方法,它的功能是一直等待,直到Done对象检测到蜘蛛程序已完成工作。下面是WaitDone方法的代码。
以下是代码片段:
publicvoidWaitDone()
{
Monitor.Enter(this);
while(m_activeThreads>0)
{
Monitor.Wait(this);
}
Monitor.Exit(this);
}
WaitDone方法将一直等待,直到不再有活动的线程。但必须注意的是,下载开始的最初阶段也没有任何活动的线程,所以很容易造成蜘蛛程序一开始就立即停止的现象。为解决这个问题,我们还需要另一个方法WaitBegin来等待蜘蛛程序进入"正式的"工作阶段。一般的调用次序是:先调用WaitBegin,再接着调用WaitDone,WaitDone将等待蜘蛛程序完成工作。下面是WaitBegin的代码:
以下是代码片段:
publicvoidWaitBegin()
{
Monitor.Enter(this);
while(!m_started)
{
Monitor.Wait(this);
}
Monitor.Exit(this);
【引自Felomeng的博客】在《爬虫/蜘蛛程序的制作(C#语言)》一文中,已经介绍了爬虫程序实现的基本方法,可以说,已经实现了爬虫的功能。只是它存在一个效率问题,下载速度可能很慢。这是两方面的原因造成的:
1.分析和下载不能同步进行。在《爬虫/蜘蛛程序的制作(C#语言)》中已经介绍了爬虫程序的两个步骤:分析和下载。在单线程的程序中,两者是无法 同时进行的。也就是说,分析时会造成网络空闲,分析的时间越长,下载的效率越低。反之也是一样,下载时无法同时进行分析,只有停下下载后才能进行下一步的 分析。问题浮出水面,我想大家都会想到:把分析和下载用不同的线程进行,问题不就解决了吗?
2.只是单线程下载。相信大家都有用过网际快车等下载资源的经历,它里面是可以设置线程数的(近年版本默认是10,曾经默认是5)。它会将文件分成 与线程数相同的部分,然后每个线程下载自己的那一部分,这样下载效率就有可能提高。相信大家都有加多线程数,提升下载效率的经历。但细心的用户会发现,在 带宽一定的情况下,并不是线程越多,速度越快,而是在某一点达到峰值。爬虫作为特殊的下载工具,不具备多线程的能力何以有效率可谈?爬虫在信息时代的目 的,难道不是快速获取信息吗?所以,爬虫需要有多线程(可控数量)同时下载网页。
好了,认识、分析完问题,就是解决问题了:
多线程在C#中并不难实现。它有一个命名空间:System.Threading,提供了多线程的支持。
要开启一个新线程,需要以下的初始化:
ThreadStart startDownload = new ThreadStart( DownLoad );
//线程起始设置:即每个线程都执行DownLoad(),注意:DownLoad()必须为不带有参数的方法
Thread downloadThread = new Thread( startDownload ); //实例化要开启的新类
downloadThread.Start();//开启线程
由于线程起始时启动的方法不能带有参数,这就为多线程共享资源添加了麻烦。不过我们可以用类级变量(当然也可以使用其它方法,笔者认为此方法最简单易用)来解决这个问题。知道开启多线程下载的方法后,大家可能会产生几个疑问:
1.如何控制线程的数量?
2.如何防止多线程下载同一网页?
3.如何判断线程结束?
4.如何控制线程结束?
下面就这几个问题提出解决方法:
1.线程数量我们可以通过for循环来实现,就如同当年初学编程的打点程序一样。
比如已知用户指定了n(它是一个int型变量)个线程吧,可以用如下方法开启五个线程。
Thread[] downloadThread;
//声名下载线程,这是C#的优势,即数组初始化时,不需要指定其长度,可以在使用时才指定。
这个声名应为类级,这样也就为其它方法控件它们提供了可能
ThreadStart startDownload = new ThreadStart( DownLoad );
//线程起始设置:即每个线程都执行DownLoad()
downloadThread = new Thread[ n ];//为线程申请资源,确定线程总数
for( int i = 0; i < n; i++ )//开启指定数量的线程数
{
downloadThread[i] = new Thread( startDownload );//指定线程起始设置
downloadThread[i].Start();//逐个开启线程
}
好了,实现控制开启线程数是不是很简单啊?
2.下面出现的一个问题:所有的线程都调用DonwLoad()方法,这样如何避免它们同时下载同一个网页呢?
这个问题也好解决,只要建立一下Url地址表,表中的每个地址只允许被一个线程申请即可。具体实现:
可以利用数据库,建立一个表,表中有四列,其中一列专门用于存储Url地址,另外两列分别存放地址对应的线程以及该地址被申请的次数,最后一列存放 下载的内容。(当然,对应线程一列不是必要的)。当有线程申请后,将对应线程一列设定为当前线程编号,并将是否申请过一列设置为申请一次,这样,别的线程 就无法申请该页。如果下载成功,则将内容存入内容列。如果不成功,内容列仍为空,作为是否再次下载的依据之一,如果反复不成功,则进程将于达到重试次数 (对应该地址被申请的次数,用户可设)后,申请下一个Url地址。主要的代码如下(以VFP为例):
<建立表>
CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I )
&&建立一个表ctablename.dbf,含有地址、文本内容、已经尝试下载次数、
线程标志(初值为-1,线程标志是从0开始的整数)四个字段
<提取Url地址>
cfullname = (ctablename) + '.dbf'&&为表添加扩展名
USE (cfullname)
GO TOP
LOCATE FOR (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND
( threadNum = thisNum OR threadNum = - 1) )
&&查找尚未下载成功且应下载的属于本线程权限的Url地址,thisNum是当前线程的编号,
可以通过参数传递得到
gotUrl = curl
recNum = RECNO()
IF recNum <= RECCOUNT() THEN &&如果在列表中找到这样的Url地址
UPDATE (cfullname) SET ldowned = ( ldowned + 1 ) , threadNum =
thisNum WHERE RECNO() = recNum &&更新表,将此记录更新为已申请,即下载次数加1,
线程标志列设为本线程的编号。
<下载内容>
cfulltablename = (ctablename) + '.dbf'
USE (cfulltablename)
SET EXACT ON
LOCATE FOR curl = (csiteurl) && csiteurl是参数,为下载到的内容所对应的Url地址
recNumNow = RECNO()&&得到含有此地址的记录号
UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() =
recNumNow &&插入对应地址的对应内容
<插入新地址>
ctablename = (ctablename) + '.dbf'
USE (ctablename)
GO TOP
SET EXACT ON
LOCATE FOR curl = (cnewurl) &&查找有无此地址
IF RECNO() > RECCOUNT() THEN &&如果尚无此地址
SET CARRY OFF
INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum )
VALUES ( (cnewurl) , "" , 0 , -1 ) &&将主页地址添加到列表
好了,这样就解决了多线程中,线程冲突。当然,去重问题也可以在C#语言内解决,只根建立一个临时文件(文本就可以),保存所有的Url地址,差对它们设置相应的属性即可,但查找效率可能不及数据库快。
共2页
3.线程结束是很难判断的,因为它总是在查找新的链接。用者认为可以假设:线程重复N次以后还是没有能申请到新的Url地址,那么可以认为它已经下载完了所有链接。主要代码如下:
string url = "";
int times = 0;
while ( url == "" )//如果没有找到符合条件的记录,则不断地寻找符合条件的记录
{
url = getUrl.GetAUrl( …… );//调用GetAUrl方法,试图得到一个url值
if ( url == "" )//如果没有找到
{
times ++;//尝试次数自增
continue; //进行下一次尝试
}
if ( times > N ) //如果已经尝试够了次数,则退出进程
{
downloadThread[i].Abort; //退出进程
}
else//如果没有尝试够次数
{
Times = 0; //尝试次数归零处理
}
//进行下一步针对得到的Url的处理
}
4.这个问题相对简单,因为在问题一中已经建议,将线程声名为类级数组,这样就很易于控制。只要用一个for循环即可结束。代码如下:
for( int i = 0; i < n; i++ )//关闭指定数量n的线程数
{
downloadThread[i].Abort();//逐个关闭线程
}
好了,一个蜘蛛程序就这样完成了,在C#面前,它的实现原来如此简单。
这里笔者还想提醒读者:笔者只是提供了一个思路及一个可以实现的解决方案,但它并不是最佳的,即使这个方案本身,也有好多可以改进的地方,留给读者思考。
最后说明一下我所使用的环境:
winXP sp2 Pro
VFP 9.0
Visual Studio 2003 .net中文企业版
Ⅳ 如何优雅地使用c语言编写爬虫
大家在平时或多或少地都会有编写网络爬虫的需求。一般来说,编写爬虫的首选自然非python莫属,除此之外,java等语言也是不错的选择。选择上述语言的原因不仅仅在于它们均有非常不错的网络请求库和字符串处理库,还在于基于上述语言的爬虫框架非常之多和完善。良好的爬虫框架可以确保爬虫程序的稳定性,以及编写程序的便捷性。所以,这个cspider爬虫库的使命在于,我们能够使用c语言,依然能够优雅地编写爬虫程序。
爬虫的特性
配置方便。使用一句设置函数,即可定义user agent,cookie,timeout,proxy以及抓取线程和解析线程的最大数量。
程序逻辑独立。用户可以分别定义爬虫的解析函数,和数据持久化函数。并且对于解析到的新url,用户可以使用cspider提供的addUrl函数,将其加入到任务队列中。
便捷的字符串处理。cspider中提供了基于pcre的简单的正则表达式函数,基于libxml2的xpath解析函数,以及用于解析json的cJSON库。
高效的抓取。cspider基于libuv调度抓取线程和解析线程,使用curl作为其网络请求库。
使用cspider的步骤
获取cspider_t。
自定义user agent,cookie,timeout,proxy以及抓取线程和解析线程的最大数量。
添加初始要抓取的url到任务队列。
编写解析函数和数据持久化函数。
启动爬虫。
例子
先来看下简单的爬虫例子,会在后面详细讲解例子。
#include<cspider/spider.h>
/*
自定义的解析函数,d为获取到的html页面字符串
*/
void p(cspider_t *cspider, char *d, void *user_data) {
char *get[100];
//xpath解析html
int size = xpath(d, "//body/div[@class='wrap']/div[@class='sort-column area']/div[@class='column-bd cfix']/ul[@class='st-list cfix']/li/strong/a", get, 100);
int i;
for (i = 0; i < size; i++) {
//将获取到的电影名称,持久化
saveString(cspider, get[i]);
}
}
/*
数据持久化函数,对上面解析函数中调用的saveString()函数传入的数据,进行进一步的保存
*/
void s(void *str, void *user_data) {
char *get = (char *)str;
FILE *file = (FILE*)user_data;
fprintf(file, "%s\n", get);
return;
}
int main() {
//初始化spider
cspider_t *spider = init_cspider();
char *agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0";
//char *cookie = "bid=s3/yuH5Jd/I; ll=108288; viewed=1130500_24708145_6433169_4843567_1767120_5318823_1899158_1271597; __utma=30149280.927537245.1446813674.1446983217.1449139583.4; __utmz=30149280.1449139583.4.4.utmcsr=accounts.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/login; ps=y; [email protected]; dbcl2=58742090:QgZ2PSLiDLQ; ck=T9Wn; push_noty_num=0; push_doumail_num=7; ap=1; __utmb=30149280.0.10.1449139583; __utmc=30149280";
//设置要抓取页面的url
cs_setopt_url(spider, "so.tv.sohu.com/list_p1100_p20_p3_u5185_u5730_p40_p5_p6_p77_p80_p9_2d1_p101_p11.html");
//设置user agent
cs_setopt_useragent(spider, agent);
//cs_setopt_cookie(spider, cookie);
//传入解析函数和数据持久化函数的指针
cs_setopt_process(spider, p, NULL);
//s函数的user_data指针指向stdout
cs_setopt_save(spider, s, stdout);
//设置线程数量
cs_setopt_threadnum(spider, DOWNLOAD, 2);
cs_setopt_threadnum(spider, SAVE, 2);
//FILE *fp = fopen("log", "wb+");
//cs_setopt_logfile(spider, fp);
//开始爬虫
return cs_run(spider);
}
例子讲解
cspider_t *spider = init_cspider();获取初始的cspider。cs_setopt_xxx这类函数可以用来进行初始化设置。其中要注意的是: cs_setopt_process(spider,p,NULL);与cs_setopt_save(spider,s,stdout);,它们分别设置了解析函数p和数据持久化函数s,这两个函数需要用户自己实现,还有用户自定义的指向上下文信息user_data的指针。
在解析函数中,用户要定义解析的规则,并对解析得到的字符串可以调用saveString进行持久化,或者是调用addUrl将url加入到任务队列中。在saveString中传入的字符串会在用户自定义的数据持久函数中得到处理。此时,用户可以选择输出到文件或数据库等。
最后调用cs_run(spider)即可启动爬虫。
具体的API参数可在这里查看
Ⅵ 除了python可以爬虫还有哪些编程语言可以爬虫
能够做网络爬虫的编程语言很多,包括PHP、Java、C/C++、Python等都能做爬虫,都能达到抓取想要的数据资源。针对不同的环境,我们需要了解他们做爬虫的优缺点,才能选出合适的开发环境。
(一)PHP
网络爬虫需要快速的从服务器中抓取需要的数据,有时数据量较大时需要进行多线程抓取。PHP虽然是世界上最好的语言,但是PHP对多线程、异步支持不足,并发不足,而爬虫程序对速度和效率要求极高,所以说PHP天生不是做爬虫的。
(二)C/C++
C语言是一门面向过程、抽象化的通用程序设计语言,广泛应用于底层开发,运行效率和性能是最强大的,但是它的学习成本非常高,需要有很好地编程知识基础,对于初学者或者编程知识不是很好地程序员来说,不是一个很好的选择。当然,能够用C/C++编写爬虫程序,足以说明能力很强,但是绝不是最正确的选择。
(三)Java
在网络爬虫方面,作为Python最大的对手Java,拥有强大的生态圈。但是Java本身很笨重,代码量大。由于爬虫与反爬虫的较量是持久的,也是频繁的,刚写好的爬虫程序很可能就不能用了。爬虫程序需要经常性的修改部分代码。而Java的重构成本比较高,任何修改都会导致大量代码的变动。
(四)Python
Python在设计上坚持了清晰划一的风格,易读、易维护,语法优美、代码简洁、开发效率高、第三方模块多。并且拥有强大的爬虫Scrapy,以及成熟高效的scrapy-redis分布式策略。实现同样的爬虫功能,代码量少,而且维护方便,开发效率高。
Ⅶ 我想用c编写一个爬虫程序,可是看完一本c语言教程后,还是觉得只会编写一些计算类的小代码,要学会编写
C++开发难度而言会大一些。你可以学学比如Python之类的,爬虫找到好用的库,没多久就能做好了。
Ⅷ 各位好,有谁做过网络蜘蛛(爬虫)啊可以提供C语言的源代码给我不啊能帮我解释一下更好,谢谢!
网上又好多,可以自己下载啊。http://bbs.chinaunix.net/thread-2163118-1-1.html
Ⅸ 怎么在DOS下用C语言写网络爬虫
获取cspider_t。
自定义user agent,cookie,timeout,proxy以及抓取线程和解析线程的最大数量。
添加初始要抓取的url到任务队列。
编写解析函数和数据持久化函数。
启动爬虫。
- #include<cspider/spider.h>
- /*
- 自定义的解析函数,d为获取到的html页面字符串
- */
- void p(cspider_t *cspider, char *d, void *user_data) {
- char *get[100];
- //xpath解析html
- int size = xpath(d, "//body/div[@class='wrap']/div[@class='sort-column area']/div[@class='column-bd cfix']/ul[@class='st-list cfix']/li/strong/a", get, 100);
- int i;
- for (i = 0; i < size; i++) {
- //将获取到的电影名称,持久化
- saveString(cspider, get[i]);
- }
- }
- /*
- 数据持久化函数,对上面解析函数中调用的saveString()函数传入的数据,进行进一步的保存
- */
- void s(void *str, void *user_data) {
- char *get = (char *)str;
- FILE *file = (FILE*)user_data;
- fprintf(file, "%s ", get);
- return;
- }
- int main() {
- //初始化spider
- cspider_t *spider = init_cspider();
- char *agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0";
- //char *cookie = "bid=s3/yuH5Jd/I; ll=108288; viewed=1130500_24708145_6433169_4843567_1767120_5318823_1899158_1271597; __utma=30149280.927537245.1446813674.1446983217.1449139583.4; __utmz=30149280.1449139583.4.4.utmcsr=accounts.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/login; ps=y; [email protected]; dbcl2=58742090:QgZ2PSLiDLQ; ck=T9Wn; push_noty_num=0; push_doumail_num=7; ap=1; __utmb=30149280.0.10.1449139583; __utmc=30149280";
- //设置要抓取页面的url
- cs_setopt_url(spider, "so.tv.sohu.com/list_p1100_p20_p3_u5185_u5730_p40_p5_p6_p77_p80_p9_2d1_p101_p11.html");
- //设置user agent
- cs_setopt_useragent(spider, agent);
- //cs_setopt_cookie(spider, cookie);
- //传入解析函数和数据持久化函数的指针
- cs_setopt_process(spider, p, NULL);
- //s函数的user_data指针指向stdout
- cs_setopt_save(spider, s, stdout);
- //设置线程数量
- cs_setopt_threadnum(spider, DOWNLOAD, 2);
- cs_setopt_threadnum(spider, SAVE, 2);
- //FILE *fp = fopen("log", "wb+");
- //cs_setopt_logfile(spider, fp);
- //开始爬虫
- return cs_run(spider);
- }
例子
先来看下简单的爬虫例子,会在后面详细讲解例子。
Ⅹ Python爬虫是什么
爬虫一般指网络资源的抓取,通过编程语言撰写爬虫工具,抓取自己想要的数据以及内容。而在众多编程语言之中,Python有丰富的网络抓取模块,因此成为撰写爬虫的首选语言,并引起了学习热潮。
Python作为一门编程语言而纯粹的自由软件,以简洁清晰的语法和强制使用空白符号进行语句缩进的特点受到程序员的喜爱。用不同编程语言完成一个任务,C语言一共要写1000行代码,Java要写100行代码,而Python只需要20行,用Python来完成编程任务代码量更少,代码简洁简短而且可读性强。
Python非常适合开发网络爬虫,因为对比其他静态编程语言,Python抓取网页文档的接口更简洁;对比其他脚本语言,Python的urllib2包提供了较为完整的访问网页文档的API。
Python爬虫的工作流程是什么?
Python爬虫通过URL管理器,判断是否有待爬URL,如果有待爬URL,通过调度器进行传递给下载器,下载URL内容,通过调度器传送给解释器,解析URL内容,将有价值数据和新的URL列表通过调度器传递给应用程序,输出价值信息的过程。
Python是一门非常适合开发网络爬虫的语言,提供了urllib、re、json、pyquery等模块,同时还有很多成型框架,比如说Scrapy框架、PySpider爬虫系统等,代码十分简洁方便,是新手学习网络爬虫的首选语言。