在现代Web开发中,提取网页中的表格数据并将其存储到数据库是一项常见且重要的任务,这一过程通常涉及多个步骤,包括抓取网页内容、解析HTML表格、处理数据以及将数据插入到数据库中,以下是一个详细的指南,介绍如何使用C语言完成这一任务。
准备工作
1 环境配置
安装必要的库:为了简化HTTP请求和HTML解析,可以使用libcurl库进行HTTP请求,使用libxml2库解析HTML。
设置编译器:确保你的系统上安装了GCC或其他支持的C编译器。
2 创建项目结构
项目目录:创建一个项目目录,例如web_table_extractor
。
文件结构:在项目目录下创建以下文件:
main.c
:主程序入口。
http_request.c
和http_request.h
:处理HTTP请求。
html_parser.c
和html_parser.h
:解析HTML并提取表格数据。
database.c
和database.h
:处理数据库连接和数据插入。
实现HTTP请求
1 编写HTTP请求模块
http_request.c
#include "http_request.h" #include <curl/curl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> size_t write_callback(void ptr, size_t size, size_t nmemb, void stream) { size_t real_size = size nmemb; charresponse = (char)stream; response = realloc(response, strlen(response) + real_size + 1); memcpy(response + strlen(response), ptr, real_size); (response)[strlen(response) + real_size] = ''; return real_size; } char fetch_url(const char url) { CURL curl; CURLcode res; char response = NULL; curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); res = curl_easy_perform(curl); if(res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s ", curl_easy_strerror(res)); free(response); response = NULL; } curl_easy_cleanup(curl); } return response; }
http_request.h
#ifndef HTTP_REQUEST_H #define HTTP_REQUEST_H char fetch_url(const char url); #endif // HTTP_REQUEST_H
解析HTML表格
1 编写HTML解析模块
html_parser.c
#include "html_parser.h" #include <libxml/HTMLparser.h> #include <libxml/xpath.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char data; size_t rows; size_t cols; } TableData; TableData parse_html_table(const char html) { htmlDocPtr doc = htmlReadMemory(html, strlen(html), NULL, NULL, HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); if(!doc) { fprintf(stderr, "Failed to parse HTML document "); exit(EXIT_FAILURE); } xmlXPathContextPtr context = xmlXPathNewContext(doc); if(!context) { fprintf(stderr, "Failed to create XPath context "); exit(EXIT_FAILURE); } xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar )"//table", context); if(!result || !result->nodesetval || result->nodesetval->nodeNr == 0) { fprintf(stderr, "No table found in HTML "); exit(EXIT_FAILURE); } xmlNodeSetPtr nodes = result->nodesetval; xmlNodePtr table = nodes->nodeTab[0]; xmlNodePtr row = NULL; xmlNodePtr cell = NULL; TableData tableData = {NULL, 0, 0}; size_t rowCount = 0; size_t colCount = 0; for(row = table->children; row; row = row->next) { if(row->type == XML_ELEMENT_NODE && !xmlStrcmp(row->name, (const xmlChar )"tr")) { if(tableData.rows == 0) { for(cell = row->children; cell; cell = cell->next) { if(cell->type == XML_ELEMENT_NODE && !xmlStrcmp(cell->name, (const xmlChar )"td")) { colCount++; } } tableData.cols = colCount; tableData.data = malloc(sizeof(char ) colCount rowCount); } size_t cellIndex = 0; for(cell = row->children; cell; cell = cell->next) { if(cell->type == XML_ELEMENT_NODE && !xmlStrcmp(cell->name, (const xmlChar )"td")) { xmlChar content = xmlNodeGetContent(cell); tableData.data[rowCount colCount + cellIndex] = strdup((const char )content); xmlFree(content); cellIndex++; } } rowCount++; } } tableData.rows = rowCount; xmlXPathFreeObject(result); xmlXPathFreeContext(context); xmlFreeDoc(doc); xmlCleanupParser(); return tableData; }
html_parser.h
#ifndef HTML_PARSER_H #define HTML_PARSER_H typedef struct { char data; size_t rows; size_t cols; } TableData; TableData parse_html_table(const char html); #endif // HTML_PARSER_H
数据库操作
1 编写数据库模块
database.c
#include "database.h" #include <mysql/mysql.h> #include <stdio.h> #include <stdlib.h> #include <string.h> MYSQL connect_db() { MYSQL conn = mysql_init(NULL); if(conn == NULL) { fprintf(stderr, "MySQL initialization failed "); return NULL; } if(!mysql_real_connect(conn, "localhost", "user", "password", "database", 0, NULL, 0)) { fprintf(stderr, "Failed to connect to database: Error: %s ", mysql_error(conn)); mysql_close(conn); return NULL; } return conn; } void insert_table_data(MYSQL conn, TableData data) { char query[1024]; snprintf(query, sizeof(query), "INSERT INTO table_data (column1, column2, ...) VALUES "); for(size_t i = 0; i < data.rows; i++) { strcat(query, "("); for(size_t j = 0; j < data.cols; j++) { char value[256]; snprintf(value, sizeof(value), "'%s'", data.data[i data.cols + j]); strcat(query, value); if(j < data.cols 1) strcat(query, ", "); } strcat(query, "), "); } query[strlen(query) 2] = ''; // Remove trailing comma and space if(mysql_query(conn, query)) { fprintf(stderr, "Failed to insert data: Error: %s ", mysql_error(conn)); } else { printf("Data inserted successfully "); } }
database.h
#ifndef DATABASE_H #define DATABASE_H #include <mysql/mysql.h> #include "table_data.h" MYSQL connect_db(); void insert_table_data(MYSQL conn, TableData data); #endif // DATABASE_H
主程序整合
main.c
#include "http_request.h" #include "html_parser.h" #include "database.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <mysql/mysql.h> int main() { const char url = "http://example.com/page"; // 替换为实际的网页URL char html = fetch_url(url); if(!html) { fprintf(stderr, "Failed to fetch URL content "); return EXIT_FAILURE; } TableData tableData = parse_html_table(html); free(html); // 释放HTTP请求获取的内存 MYSQL conn = connect_db(); if(!conn) { fprintf(stderr, "Failed to connect to database "); return EXIT_FAILURE; } insert_table_data(conn, tableData); mysql_close(conn); // 关闭数据库连接 for(size_t i = 0; i < tableData.rows; i++) { for(size_t j = 0; j < tableData.cols; j++) { free(tableData.data[i tableData.cols + j]); // 释放解析后的表格数据内存 } } free(tableData.data); // 释放表格数据指针数组内存 return EXIT_SUCCESS; }
编译与运行
确保安装了libcurl、libxml2和MySQL开发库后,使用以下命令编译:
gcc -o web_table_extractor main.c http_request.c html_parser.c database.c -lcurl -lxml2 -lmysqlclient -lm -lpthread
然后运行程序:
./web_table_extractor
如果一切正常,程序将从指定的URL抓取网页,解析其中的表格数据,并将其插入到MySQL数据库中。
FAQs(常见问题解答)
Q1: 如果网页结构发生变化,如何调整代码以适应新的结构?
A1: 如果网页结构发生变化,需要更新parse_html_table
函数中的XPath表达式以匹配新的表格结构,如果表格的XPath从//table
变为//div[@id='new-table']/table
,则需要相应地修改代码,确保解析逻辑能够正确处理新的单元格和行结构,如果表格的列数或格式发生变化,也需要调整insert_table_data
函数中的SQL查询语句,以确保数据正确插入数据库,建议定期检查和维护代码,以应对可能的结构变化。
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1657819.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。