C++ 实现网络爬虫_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > C++ 实现网络爬虫

C++ 实现网络爬虫

 2014/8/24 18:39:10  落单的毛毛虫  程序员俱乐部  我要评论(0)
  • 摘要:吐槽前天心血来潮,把自己面试经历下了下来.我觉得自己求职一路来比较心酸,也付出了比一般人更多的汗水.本以为写出来,好歹可以作为一篇励志故事.得到的评论却是,语言只是一门工具.|||这句话我已经听了4年了!我以前也是XX,现在XXX.|||直到你膝盖中了一箭?我也是用c的...只能说,重要的是一种学习的能力,会用即可.|||呵呵.可能能对于你的同学,你是优秀的,但是可能对于你想工作的方向的公司来说,你会的太少,不值得一些公司去培养,所以还是建议你把基础再好好踏实一下更有利
  • 标签:实现 c++ 网络 网络爬虫

吐槽

前天心血来潮, 把自己面试经历下了下来.

我觉得自己求职一路来比较心酸, 也付出了比一般人更多的汗水.

本以为写出来, 好歹可以作为一篇励志故事.

得到的评论却是, 

  语言只是一门工具. ||| 这句话我已经听了4年了!

  我以前也是XX, 现在XXX. ||| 直到你膝盖中了一箭?

  我也是用c的...只能说,重要的是一种学习的能力,会用即可. ||| 呵呵.

  可能能对于你的同学,你是优秀的,但是可能对于你想工作的方向的公司来说,你会的太少,不值得一些公司去培养,所以还是建议你把基础再好好踏实一下更有利。

最后一句话是让我最不爽的.

现在的人啊, 看什么就是什么, 以偏概全, 

上的大学不好,  从入大学到大学毕业, 这经过了多少年, 从这多少年前就注定的事能认定这个人现在的水平么?

 

网投了几百份简历, 没有收到一个面试通知, 

直接去公司霸面, 面了2个, 过了2个.

难道这个问题不是出在简历上?

 

突然就想起了找工作那段时间, 我在某群发了一条挂广告.

立马就有人出来扮演一位阅人无数的高人.

直言说, 你要是很优秀早就有人抢去了, 还是报个培训机构吧.

 

C++程序员都明白, C++成型慢, 一般公司都不会用新人, 更别说专科毕业的了.

那些习惯了速成的人是不会明白的.

好了, 吐槽完毕. 切换模式.

C++实现网络爬虫

#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <string>
#include <utility>
#include <regex>
#include <fstream>
#include <WinSock2.h>
#include <Windows.h>

#pragma comment(lib, "ws2_32.lib")

using namespace std;

void startupWSA()
{
    WSADATA wsadata;
    WSAStartup( MAKEWORD(2,0), &wsadata);
}

inline void cleanupWSA()
{
    WSACleanup();
}

inline pair<string, string> binaryString(const string &str, const string &dilme)
{
    pair<string, string> result(str, "");
    auto pos = str.find(dilme);
    if ( pos != string::npos )
    {
        result.first = str.substr(0, pos);
        result.second = str.substr(pos + dilme.size());
    }
    return result;
}

inline string getIpByHostName(const string &hostName)
{
    hostent* phost = gethostbyname( hostName.c_str() );
    return phost? inet_ntoa(*(in_addr *)phost->h_addr_list[0]): "";
}

inline SOCKET connect(const string &hostName)
{
    auto ip = getIpByHostName(hostName);
    if ( ip.empty() )
        return 0;
    auto sock = socket(AF_INET, SOCK_STREAM, 0);
    if ( sock == INVALID_SOCKET )
        return 0;
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    if ( connect(sock, (const sockaddr *)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR )
        return 0;
    return sock;
}

inline bool sendRequest(SOCKET sock, const string &host, const string &get)
{
    string http 
        = "GET " + get + " HTTP/1.1\r\n"
        + "HOST: " + host + "\r\n"
        + "Connection: close\r\n\r\n";
    return http.size() == send(sock, &http[0], http.size(), 0);
}

inline string recvRequest(SOCKET sock)
{
    static timeval wait = {2, 0};
    static auto buffer = string(2048 * 100, '\0');
    auto len = 0, reclen = 0;
    do {
        fd_set fd = {0};
        FD_SET(sock, &fd);
        reclen = 0;
        if ( select(0, &fd, nullptr, nullptr, &wait) > 0 )
        {
            reclen = recv(sock, &buffer[0] + len, 2048 * 100 - len, 0);
            if (reclen > 0)
                len += reclen;
        }
        FD_ZERO(&fd);
    } while (reclen > 0);

    return len > 11
        ? buffer[9] == '2' && buffer[10] == '0' && buffer[11] == '0'
        ? buffer.substr(0, len)
        : ""
        : "";
}

inline void extUrl(const string &buffer, queue<string> &urlQueue)
{
    if (buffer.empty())
    {
        return ;
    }
    smatch result;
    auto curIter = buffer.begin();
    auto endIter = buffer.end();
    while ( regex_search(curIter, endIter, result, regex("href=\"(https?:)?//\\S+\"") ) )
    {
        urlQueue.push(regex_replace(
            result[0].str(), 
            regex("href=\"(https?:)?//(\\S+)\""),
            "$2") );
        curIter = result[0].second;
    }
}

void Go(const string &url, int count)
{
    queue<string> urls;
    urls.push(url);
    for (auto i = 0; i != count; ++i)
    {
        if ( !urls.empty() )
        {
            auto &url = urls.front();
            auto pair = binaryString( url, "/" );
            auto sock = connect(pair.first);
            if ( sock && sendRequest(sock, pair.first, "/" + pair.second) )
            {
                auto buffer = move( recvRequest(sock) );
                extUrl(buffer, urls);
            }
       closesocket(sock); cout
<< url << ": count=> " << urls.size() << endl; urls.pop(); } } } int main() { startupWSA(); Go("www.hao123.com", 200); cleanupWSA(); return 0; }

该爬虫只花了1个小时左右.

其实我想说, 写的很烂, 大伙不要喷.

 

http协议, socket, 正则表达式咱们就不说了..

说说这个原理, 

所有的 URL 全都放在 urls 这个队列中.

首先要 push 一个根 URL.

之后爬虫就行动了.

过程大概是这样:

从urls取出一个URL => 读出URL网页全部内容 => 分析所有URL => 把URL放进 urls => 从 urls 弹出一个 URL.

 

URL 是 host + get.

因此需要一个 binaryString 把它切开.

效率也不是很快, 1分钟大概4W条URL, 去掉重复至少也有好几千吧.

 

有一点需要注意.

C++11 的正则表达式真心有点难用~~~

我不知道怎么多次匹配..

只好用一个循环了..

网上搜出来一个答案,  写法有点莫名其妙..

执行结果

发表评论
用户名: 匿名