基于C++的Proxy list spider编写历程

1、首先熟悉怎样将网页的html文件下载到本地,因为C++部分是作为一个exe进行调用,所以不考虑使用MFC中的相关类,于是上网搜了一下,发现使用libcurl可以比较好地进行下载HTML文件,虽然这样做将libcurl的功能发挥的较为局限,可谓是大材小用了,不过既然网上有现有的代码所以就直接使用网上拥有的使用libcurl进行网页HTML下载的代码了。
#include
#include
#include   
    
    
    //这是libcurl接收数据的回调函数,相当于recv的死循环  
    //其中stream可以自定义数据类型,这里我传入的是文件保存路径  
    static size_t write_callback( void *ptr, size_t size, size_t nmemb, void *stream )  
    {  
        int len = size * nmemb;  
        int written = len;  
        FILE *fp = NULL;  
          
        if ( access( (char*)stream, 0 ) == -1 )  
        {  
            fp = fopen( (char*) stream, "wb" );  
        }  
        else  
        {  
            fp = fopen( (char*) stream, "ab" );  
        }  
        if (fp)  
        {  
            fwrite( ptr, size, nmemb, fp );  
        }  
        return written;  
    }  
    int GetUrl( const char *url, char *savepath )  
    {  
        CURL *curl;  
        CURLcode res;  
        struct curl_slist *chunk = NULL;  
        curl_global_init(CURL_GLOBAL_ALL);
        curl = curl_easy_init();  
        if ( curl ) {  
            curl_easy_setopt( curl, CURLOPT_VERBOSE, 0L );
            curl_easy_setopt( curl, CURLOPT_URL, url );
                    //指定回调函数  
            curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_callback);
                    //这个变量可作为接收或传递数据的作用  
            curl_easy_setopt( curl, CURLOPT_WRITEDATA, savepath );
            res = curl_easy_perform( curl );
            if (res == CURLE_OK)  
            {  
                return 1;  
            }  
            return 0;  
        }  
    }  
    int main()  
    {  
        if ( GetUrl( "http://www.google.com.hk/search?q=proxy+list&start=20", "2.xml" ) )  
        {  
            printf( "OK" );  
        }  
        return 0;  
    } 

这里传入的url根据google的连接特性给出,很容易知道关键词即q=后面的字符串,而第几页就是start=后面的数字。然后进行编译运行就可以下载相应的Google的HTML页面了。

2、解析HTML页面:

       首先有两部分需要进行操作,第一部分是先从Google上解析出具有proxy list的网页的url,然后进入这个url进行proxy list的解析。在这里就有一些问题了,首先无法知道从google上解析出的网页URL进入之后主页面是否有Proxy list,其次是一般一个proxy list会有好几页,怎样实现翻页的功能。因为在这里每个网页的结构不一致,所以我无法实现每个网页的proxy list进行翻页的操作,所以在这里就直接找主页上的Proxy list然后进行解析到本地就行了。

       研究过google的网页源码的同学都应该知道具体的结构,在这里也可以使用相应的xml解析库进行解析,但是由于C++这方面的库比较少,之前准备使用tinyxml库进行解析,然后发现如果将tinyxml进行解析后的文件直接存入文件中的话就会失去一部分信息,所以tinyxml的使用失败了,然后考虑了相关的html解析库像htmlcxx,这个库应该能够实现相应的解析功能,不过由于google网页源码的特殊性,由关键词搜索出的url会包括在两个特定的字符串之间,所以利用这个特性,将下载好的HTML文件进行逐行读取,然后根据这个特性进行解析就可以解析出相应的URL了,下面是源代码

#include
#include
#include
#include


using namespace std;

int main(){
	char buf[1027]={0};
	string str;
	bool find_flag = false;
	const string str_google_begin("

        在解析出具有Proxy list的URL之后,使用boost所带有的regex类库进行正则匹配,找到满足ip:port类型的字符串然后提取出来,至于boost的编译过程较为繁琐推荐查看http://www.cnblogs.com/wondering/archive/2009/05/21/boost_setup.html所写的内容进行相应操作,其中有关boost regex中的正则表达式的操作则可以查看学习http://www.cppblog.com/ming81/archive/2011/05/04/145686.html

通过将URL对应的HTML网页文件下载到本地缓存然后通过读取这个缓存文件进行相关操作就可以达成选取匹配出文件中的所有满足ip:port的字符串。

void Analyse_Proxy(const char* path)
{    
	const char *szReg = "((\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3}):(\\d{1,5}))";
	char buf[1027]={0};
	string str;
	FILE *fp=fopen(path,"r");
	int ii = 0;
	while(fgets(buf,1027,fp)!=NULL){
		
		str = buf;
		const char* szStr = str.c_str();


		//使用迭代器找出所有ip:port

		boost::regex reg(szReg );   
		boost::cregex_iterator itrBegin = make_regex_iterator(szStr,reg); //(szStr, szStr+strlen(szStr), reg);
		boost::cregex_iterator itrEnd;
		for(boost::cregex_iterator itr=itrBegin; itr!=itrEnd; ++itr)
		{
			//子串内容
			cout <<*itr << endl;
		}
		//ii++;
	}
	//cout<
4、前三个小模块做完之后进行大模块功能的整合,完成一个调用者输入搜索关键词然后调用exe然后获得返回值的大模块。然后继续编写验证服务器是否可用的模块,这个模块被第三个模块调用,然后调用的结果返回一个true or false,最后将这个状态连接到字符串中就可以进行打印输出了。验证服务器是否可用模块暂时还没开始着手动工,所以这里仅仅是一个想法,之后会补充完整。


由于这个项目是使用C#实现界面C++实现功能的基础上完成的,所以在这里就直接使用C#中的有关网络连接的方式进行验证,通过C#中的网络访问有关类来进行代理服务器的设置,以百度为测试网站,不过这种做法所带来的不好的地方就是验证时间过长,需要设置一个最长等待时间,对于服务器这种方式来说,可能在国外的代理服务器可用但是延迟时间过长会产生误判,但是这里如果使用某些验证代理服务器是否可用的服务器的话涉及到一些POST操作,比较繁琐,所以在这里就不使用这种方式了。下面是验证服务器是否可用的代码

public static Boolean CheckProxy(String IP, int Port)
        {
            HttpWebRequest objHttpRequest;
            HttpWebResponse objResponse;
            WebProxy objProxy;
            objHttpRequest = (HttpWebRequest)WebRequest.Create("http://www.baidu.com"); //设定测试页面,用百度来测试
            objHttpRequest.Timeout = 1000; //设定超时时间
            objHttpRequest.AllowAutoRedirect = true;
            objHttpRequest.ContentType = "application/x-www-form-Urlencoded";

            objProxy = new WebProxy(IP, Port);
            objProxy.BypassProxyOnLocal = true;

            objHttpRequest.Proxy = objProxy;
            try
            {
                objResponse = (HttpWebResponse)objHttpRequest.GetResponse();
            }
            catch (Exception)
            {
                return false; //无法使用或超时
            }
            return true; //可以使用
        }

5、最后通过线程来启动进程的方式实现多进程的程序启动。


你可能感兴趣的:(C++/windows)