如何用好C语言来做爬虫,想必接触过的大神都能说扥头头是道,但是对于新手小白来说,有这么几点需要注意的。根据设计程序结构,我们需要一个队列来管理待爬取的URL,一个集合或列表来记录已访问的URL。主循环从队列中取出URL,发送请求,解析内容,提取新URL,处理并加入队列。这里需要注意控制并发请求的数量,避免被目标服务器封禁,或者遵守robots.txt,但基础版本可能先不考虑这些,后续可以根据需求像高并发量扩展方向,辅以代理ip能让线程超多爬取。
以下是一个基于C语言实现的简单网络爬虫示例,使用 libcurl 和 libxml2 库完成HTTP请求和HTML解析。该爬虫能够抓取指定起始URL的页面并提取其中的链接。
实现步骤说明
依赖库安装
# Ubuntu/Debiansudo apt-get install libcurl4-openssl-dev libxml2-dev代码实现
#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 = "Example Domain"; // 起始URL crawl_url(start_url); return 0;}编译指令
gcc crawler.c -o crawler -lcurl -lxml2
功能说明
HTTP请求处理
使用 libcurl 发送GET请求并处理响应。
支持自动重定向(CURLOPT_FOLLOWLOCATION)。
自定义User-Agent避免被简单拦截。
HTML解析
使用 libxml2 的XPath功能提取所有 <a> 标签的 href 属性。
自动处理不规范的HTML(通过 HTML_PARSE_RECOVER 模式)。
内存管理
动态分配内存存储网页内容,使用后释放。
扩展建议
URL去重
添加哈希表(如 uthash 库)记录已访问的URL,避免重复抓取。
多线程
使用 pthread 实现多线程并发抓取,提升效率。
遵守Robots协议
在抓取前检查目标网站的 /robots.txt,解析禁止抓取的路径。
链接标准化
将相对路径转换为绝对URL(例如 /about → Example Domain
注意事项
法律与伦理:确保遵守目标网站的 robots.txt 和服务条款,避免高频请求导致服务器过载。
错误处理:代码中省略了部分错误处理以简化示例,实际应用需完善。
性能优化:可根据需求添加DNS缓存、连接复用等机制。
上面这个示例我只是给大家提供了一个基础的爬虫框架,具体情况大家可以可根据具体需求进一步扩展功能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。