c++爬虫讲解

你们要的c++爬虫讲解,来了

在讲解c++爬虫之前,首先要了解爬虫的工作原理(知道的可跳过)

爬虫,并不是主动获取信息,而是向网页主机发送请求,网页根据请求返回信息。具体的
过程可以表述成以下几点:
1.写请求书
    请求网页返回信息前,你要用一个请求书发起请求。请求书的格式称作http消息结构,
大抵如下:
        请求方法 空格 url(子文件名) 空格 协议版本 回车 换行
        头部字段名:值 回车 换行
        ....(重复上一行格式)
    其中,请求方法就是python爬虫requests库中get、post等方法,注意要全部大写
    url子文件名是去掉http://后,第一个斜线后的内容
    协议版本是指http协议(超文本传输协议)的版本,一般填HTTP/1.1
    头部字段名和值根据不同情况填写,但是应该有下面一行:
        Host: 主机名
    主机名就是去掉http之外,第一个斜线前的内容,如www.baidu.com ,等
    示例:爬取百度源代码的请求书
        GET / HTTP/1.1
        User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
        Host: www.baidu.com
        Accept-Language: en, mi
2.创建套接字
    写好了请求书,得有一个信封把他装起来,这个信封就是套接字(socket)。套接字里有网站
    地址、端口号、请求书等等。这个过程比较简单,就不多讲了
3.把套接字发出去
    通过send函数,我们可以把套接字发出去,让网站去读取请求。
4.接收信息
    网站收到了请求,会做出回应,然后发回来,我们要做的就是定义一个大小足够的变量,存储信息。但是
    接受数据用的recv函数可能不会一次全部接受回来,于是我们就要通过while循环,一次一次地接受信息。
    接受完信息后,你会发现正文前有一段响应头,大概如下:
        HTTP/1.1 200 OK
        Date: Fri,24 Dec 2022 12:28:53 GMT
        Server: Apache
        Last-Modified: Thu, 23 Dec 2022 19:15:56 GMT
        ETag: "34aa387-d-1568eb00"
        Accept-Ranges: bytes
        Content-Length: 51
        Vary: Accept-Encoding
        Content-Type: text/plain
    这可能会对数据分析产生干扰,这时候就要用正则表达式或其他什么东西把他去掉,当然如果不影响也行
以上四步是爬虫需要经历的四步。我们在做python爬虫时,之所以不用这么麻烦,是应为requests和其他爬虫
库已经帮你把他封装成函数了。
那么接下来,开始正式代码讲解


#include <stdio.h>
#include <wchar.h>
#include <locale.h>
#include <bits/stdc++.h>
#include <iostream>
#include <string>
#include <netdb.h>
#include <string.h>
#include <regex.h>
#include <stdlib.h>

using namespace std;
 
void parseHostAndPagePath(const string url,string &hostUrl,string &pagePath){
    //将url转化成无http或https的形式
    hostUrl=url;
    pagePath="/";//
    int pos=hostUrl.find("http://");//第一步查找http(if不加大括号只能运行下一行)
    if(-1!=pos)
        hostUrl=hostUrl.replace(pos,7,"");//替换http
    pos=hostUrl.find("https://");//第二步查找http
    if(-1!=pos)
        hostUrl=hostUrl.replace(pos,8,"");//再替换http
    pos=hostUrl.find("/");//第三步查找斜线
    if(-1!=pos)
    {
        pagePath=hostUrl.substr(pos);//只保存第一个斜线前的url
        hostUrl=hostUrl.substr(0,pos);//保留斜线后的子文件名
    }//存储数据
}
string getPageContent(const string url){//发起请求
    struct hostent *host;
    string hostUrl,pagePath;
    parseHostAndPagePath(url,hostUrl,pagePath);//调用上一个函数,抽取斜线前的url
    if(0==(host=gethostbyname(hostUrl.c_str())))//这个函数返回网站的主机信息,返回结构体
    {
        cout<<"gethostbyname error\n"<<endl;//若获取主机名失败,抛出错误
        exit(1);
    }
    struct sockaddr_in pin;//调用地址结构体
    int port=80;
    bzero(&pin,sizeof(pin));//清空pin的内存
    pin.sin_family=AF_INET;//传输使用ipv4的地址族
    pin.sin_port=htons(port);//sin_port确定传输端口,htons将端口号转为主机可以接受的数据类型
    pin.sin_addr.s_addr=((struct in_addr*)(host->h_addr))->s_addr;//确定主机地址
    //注:以上均是在给地址结构体pin赋值,相当于在给信填地址
    int isock;//isock 用于检测创建成功与否
    if((isock=socket(AF_INET,SOCK_STREAM,0))==-1)//创建了套接字
    {
        cout<<"open socket error\n"<<endl;//创建套接字
        exit(1);
    }
    string requestHeader;//写请求正文
    requestHeader="GET "+pagePath+" HTTP/1.1\r\n";
    requestHeader+="Host: "+hostUrl+"\r\n";
    requestHeader+="Accept: */*\r\n";
    requestHeader+="User-Agent: Mozilla/4.0(compatible)\r\n";
    requestHeader+="connection:Keep-Alive\r\n";
    requestHeader+="\r\n";
    if(connect(isock,(const sockaddr*)&pin,sizeof(pin))==-1){//开始与网站主机连接,需代入套接字信息
        cout<<"connect error\n"<<endl;//返回值为-1即为连接失败
        exit(1);
    }
    if(send(isock,requestHeader.c_str(),requestHeader.size(),0)==-1){//发送请求正文,c_str函数将string转换成const char*
        cout<<"send error\n"<<endl;
        exit(1);
    }
    struct timeval timeout={1,0};//设置时间限制
    setsockopt(isock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(struct timeval));//发送时限
    char c;
    bool flag=true;//准备接收数据
    while(recv(isock,&c,1,0)>0){
        if('\r'==c){
            continue;
        }else if('\n'==c){
            if(false==flag)
            break;
            flag=false;
        }else{
            flag=true;
        }
        }
        int len,BUFFER_SIZE=512;
        char buffer[BUFFER_SIZE];//一次接受数据的大小
        string pageContent="";//存储内容
        while((len=recv(isock,buffer,BUFFER_SIZE-1,0))>0){//用循环分批接收数据
            buffer[len]='\0';
            pageContent+=buffer;//将接收数据一步步存储在pageContent中
        }
        return pageContent;
}
int main() {
    
    string f;
    cin>>f;
    cout<<getPageContent(f);//调用函数,获取网页源代码
    return 0;
}

不喜勿喷~~

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值