基于C语言实现网络爬虫程序设计

如何用好C语言来做爬虫,想必接触过的大神都能说扥头头是道,但是对于新手小白来说,有这么几点需要注意的。根据设计程序结构,我们需要一个队列来管理待爬取的URL,一个集合或列表来记录已访问的URL。主循环从队列中取出URL,发送请求,解析内容,提取新URL,处理并加入队列。这里需要注意控制并发请求的数量,避免被目标服务器封禁,或者遵守robots.txt,但基础版本可能先不考虑这些,后续可以根据需求像高并发量扩展方向,辅以代理ip能让线程超多爬取。

在这里插入图片描述

以下是一个基于C语言实现的简单网络爬虫示例,使用 libcurl 和 libxml2 库完成HTTP请求和HTML解析。该爬虫能够抓取指定起始URL的页面并提取其中的链接。

实现步骤说明

  1. 依赖库安装

    # Ubuntu/Debian
    sudo apt-get install libcurl4-openssl-dev libxml2-dev
    
  2. 代码实现

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <curl/curl.h>
    #include <libxml/HTMLparser.h>
    #include <libxml/xpath.h>
    
    // 存储HTTP响应内容的结构体
    struct MemoryStruct {
        char *memory;
        size_t size;
    };
    
    // libcurl回调函数:将响应内容写入内存
    static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
        size_t realsize = size * nmemb;
        struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
        mem->memory = realloc(mem->memory, mem->size + realsize + 1);
        if (mem->memory == NULL) {
            printf("内存分配失败!\n");
            return 0;
        }
    
        memcpy(&(mem->memory[mem->size]), contents, realsize);
        mem->size += realsize;
        mem->memory[mem->size] = 0; // Null-terminate
    
        return realsize;
    }
    
    // 从HTML中提取所有链接
    void extract_links(const char *html_content, const char *base_url) {
        xmlDoc *doc = htmlReadDoc((const xmlChar*)html_content, base_url, NULL, HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING);
        if (doc == NULL) return;
    
        xmlXPathContext *context = xmlXPathNewContext(doc);
        if (context == NULL) {
            xmlFreeDoc(doc);
            return;
        }
    
        // XPath表达式查找所有<a>标签的href属性
        xmlXPathObject *result = xmlXPathEvalExpression((const xmlChar*)"//a/@href", context);
        if (result == NULL) {
            xmlXPathFreeContext(context);
            xmlFreeDoc(doc);
            return;
        }
    
        // 遍历结果并打印链接
        xmlNodeSet *nodeset = result->nodesetval;
        for (int i = 0; i < nodeset->nodeNr; i++) {
            xmlChar *href = xmlNodeListGetString(doc, nodeset->nodeTab[i]->children, 1);
            printf("发现链接: %s\n", href);
            xmlFree(href);
        }
    
        // 清理资源
        xmlXPathFreeObject(result);
        xmlXPathFreeContext(context);
        xmlFreeDoc(doc);
    }
    
    // 抓取指定URL的页面内容
    void crawl_url(const char *url) {
        CURL *curl_handle;
        CURLcode res;
        struct MemoryStruct chunk;
    
        chunk.memory = malloc(1); // 初始化为空
        chunk.size = 0;
    
        curl_global_init(CURL_GLOBAL_ALL);
        curl_handle = curl_easy_init();
    
        // 设置CURL选项
        curl_easy_setopt(curl_handle, CURLOPT_URL, url);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
        curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Mozilla/5.0 (兼容性爬虫)");
        curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); // 跟随重定向
    
        // 执行请求
        res = curl_easy_perform(curl_handle);
    
        if (res != CURLE_OK) {
            fprintf(stderr, "请求失败: %s\n", curl_easy_strerror(res));
        } else {
            printf("成功抓取: %s (%zu字节)\n", url, chunk.size);
            extract_links(chunk.memory, url); // 解析链接
        }
    
        // 清理资源
        curl_easy_cleanup(curl_handle);
        free(chunk.memory);
        curl_global_cleanup();
    }
    
    int main() {
        const char *start_url = "http://example.com"; // 起始URL
        crawl_url(start_url);
        return 0;
    }
    
  3. 编译指令

    gcc crawler.c -o crawler -lcurl -lxml2
    

功能说明

  1. HTTP请求处理

    • 使用 libcurl 发送GET请求并处理响应。
    • 支持自动重定向(CURLOPT_FOLLOWLOCATION)。
    • 自定义User-Agent避免被简单拦截。
  2. HTML解析

    • 使用 libxml2 的XPath功能提取所有 <a> 标签的 href 属性。
    • 自动处理不规范的HTML(通过 HTML_PARSE_RECOVER 模式)。
  3. 内存管理

    • 动态分配内存存储网页内容,使用后释放。

扩展建议

  1. URL去重

    • 添加哈希表(如 uthash 库)记录已访问的URL,避免重复抓取。
  2. 多线程

    • 使用 pthread 实现多线程并发抓取,提升效率。
  3. 遵守Robots协议

    • 在抓取前检查目标网站的 /robots.txt,解析禁止抓取的路径。
  4. 链接标准化

    • 将相对路径转换为绝对URL(例如 /abouthttp://example.com/about)。

注意事项

  • 法律与伦理:确保遵守目标网站的 robots.txt 和服务条款,避免高频请求导致服务器过载。
  • 错误处理:代码中省略了部分错误处理以简化示例,实际应用需完善。
  • 性能优化:可根据需求添加DNS缓存、连接复用等机制。

上面这个示例我只是给大家提供了一个基础的爬虫框架,具体情况大家可以可根据具体需求进一步扩展功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值