PHP采集数据怎么入库

wen PHP项目 5

本文目录导读:

PHP采集数据怎么入库

  1. 第一步:环境准备(必装扩展)
  2. 第二步:数据库表设计
  3. 第三步:PHP采集与入库完整代码
  4. 第四步:高级优化与避坑指南
  5. 第五步:命令行脚本(推荐使用)
  6. 总结流程图

在PHP中采集数据并入库,主要涉及三个核心步骤:采集(抓取)解析(提取)存储(入库)

下面给你一个完整的实战流程和代码示例,并附上一些常见的坑和最佳实践。


第一步:环境准备(必装扩展)

在开始之前,请确认你的PHP环境已开启以下扩展:

  • curl:用于抓取网页(比 file_get_contents 更稳定,支持模拟浏览器)。
  • pdomysqli:用于连接数据库。
  • mbstringDOMDocument:用于解析HTML。

第二步:数据库表设计

假设我们要采集“商品列表”,MySQL建表语句如下:

CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT, varchar(255) NOT NULL COMMENT '标题',
  `price` decimal(10,2) DEFAULT NULL COMMENT '价格',
  `detail_url` varchar(500) DEFAULT NULL COMMENT '详情页URL',
  `image` varchar(500) DEFAULT NULL COMMENT '图片链接',
  `source_hash` varchar(32) DEFAULT NULL COMMENT 'URL去重哈希',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_hash` (`source_hash`) -- 防止重复采集
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

关键点source_hash 字段用于URL去重,使用 md5($url) 存入,并在数据库设置唯一索引,避免重复入库。


第三步:PHP采集与入库完整代码

<?php
/**
 * PHP 采集数据入库 Demo
 */
// ---------- 1. 数据库连接 (PDO) ----------
$dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8mb4';
$user = 'root';
$pass = 'password';
try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die('数据库连接失败: ' . $e->getMessage());
}
// ---------- 2. 采集函数 (cURL) ----------
function curl_get($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 如果网站是https,暂时关闭证书验证
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);    // 允许跳转
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); // 模拟浏览器
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);          // 超时时间
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
}
// ---------- 3. 解析HTML (DOMDocument + XPath) ----------
function parse_html($html) {
    $dom = new DOMDocument();
    // 屏蔽解析HTML时的警告
    libxml_use_internal_errors(true);
    $dom->loadHTML('<?xml encoding="utf-8"?>' . $html); // 避免中文乱码
    libxml_clear_errors();
    $xpath = new DOMXPath($dom);
    $items = [];
    // 这里以某网站为例,假设商品标题在 .item-title 类中,价格在 .item-price 类中
    $titles = $xpath->query('//h3[@class="item-title"]/a');
    $prices = $xpath->query('//span[@class="item-price"]');
    $links = $xpath->query('//h3[@class="item-title"]/a');
    foreach ($titles as $i => $title_node) {
        $items[] = [
            'title' => trim($title_node->textContent),
            'price' => (float) str_replace(['¥', ','], '', $prices->item($i)->textContent),
            'url' => $links->item($i)->getAttribute('href'),
            'image' => '' // 可根据实际情况提取
        ];
    }
    return $items;
}
// ---------- 4. 入库逻辑(使用预处理+事务) ----------
function insert_db($pdo, $items) {
    // 预处理SQL,防止SQL注入
    $sql = "INSERT INTO products (title, price, detail_url, image, source_hash) 
            VALUES (:title, :price, :url, :image, :hash)";
    $stmt = $pdo->prepare($sql);
    $pdo->beginTransaction(); // 开启事务,加快插入速度
    $count = 0;
    foreach ($items as $item) {
        $hash = md5($item['url']); // 生成URL哈希
        try {
            $stmt->execute([
                ':title' => $item['title'],
                ':price' => $item['price'],
                ':url' => $item['url'],
                ':image' => $item['image'],
                ':hash' => $hash,
            ]);
            $count++;
        } catch (PDOException $e) {
            // 如果唯一索引冲突(说明已存在),则跳过
            if ($e->getCode() == 23000) {
                continue; 
            } else {
                // 其他错误,回滚
                $pdo->rollBack();
                throw $e;
            }
        }
    }
    $pdo->commit();
    echo "成功入库 {$count} 条数据\n";
}
// ---------- 5. 主流程 ----------
$target_url = 'https://example.com/products'; // 替换为你要采集的目标网址
// 抓取
$html = curl_get($target_url);
if (empty($html)) {
    die('抓取失败,页面为空');
}
// 解析
$items = parse_html($html);
// 入库
insert_db($pdo, $items);
echo "采集完成,本次共处理 " . count($items) . " 条数据。\n";

第四步:高级优化与避坑指南

防封IP(代理池)

采集频繁会导致IP被封,建议设置 curl_setopt($ch, CURLOPT_PROXY, 'http://代理IP:端口') 或使用随机延迟。

// 每次请求后随机暂停 0.5~2秒
usleep(rand(500000, 2000000));

处理异步加载的数据(AJAX)

如果目标网页是动态加载的(如API接口返回JSON),直接用cURL拿到的是空壳,你需要:

  • 打开浏览器F12 -> Network,找到XHR请求的URL。
  • 直接采集那个API地址,拿到JSON数据后,用 json_decode() 解析入库。

相对路径转绝对路径

页面里的链接可能都是相对路径(如 /product/123.html),入库前需要拼成绝对URL:

$base_url = 'https://example.com';
if (strpos($link, 'http') !== 0) {
    $link = rtrim($base_url, '/') . '/' . ltrim($link, '/');
}

数据清洗

  • trim() 去除多余空格。
  • 价格去符号:str_replace(['¥', '$', ','], '', $str)
  • 转义HTML实体:htmlspecialchars_decode($str)

批量入库(性能优化)

如果每天采集上万条,逐条 execute 太慢,改用 批量插入

$values = [];
$placeholders = [];
foreach ($items as $item) {
    $placeholders[] = "(?, ?, ?, ?, ?)";
    $values = array_merge($values, [$item['title'], $item['price'], $item['url'], $item['image'], md5($item['url'])]);
}
$sql = "INSERT INTO products (title, price, detail_url, image, source_hash) VALUES " . implode(",", $placeholders);
$pdo->executeQuery($sql, $values);

第五步:命令行脚本(推荐使用)

将上述代码保存为 spider.php,在命令行运行(避免网页执行超时):

php spider.php

如果你想在浏览器中运行且数据量很大,记得在脚本开头设置:

set_time_limit(0);

总结流程图

[cURL抓取] → [DOM解析/正则提取] → [数据清洗] → [MD5去重] → [PDO预处理入库]

你只需要根据目标网页的HTML结构调整 parse_html() 函数中的 XPath 或正则表达式即可,如果遇到复杂登录的情况,还需要用 curl_setopt 携带Cookie或使用Session。

抱歉,评论功能暂时关闭!