示例
一、抓取百度分类

文档:https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi

1、获取分类

header("Content-Type:text/html;charset=utf8");
$url = 'https://lbsyun.baidu.com/index.php?title=lbscloud/poitags';

$ch = curl_init();                          // 创建一个新cURL资源
curl_setopt($ch, CURLOPT_URL, $url);         // 设置URL
curl_setopt($ch, CURLOPT_TIMEOUT, 30);      // 设置超时限制防止死循环
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// 爬取重定向页面
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);   // 自动设置Referer,防止盗链
curl_setopt($ch, CURLOPT_HEADER, 0);        // 显示返回的Header区域内容
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 要求结果保存到字符串中还是输出到屏幕上
curl_setopt($ch, CURLOPT_USERAGENT, 'Data');// 在HTTP请求中包含一个"User-Agent: "头的字符串。

$html = curl_exec($ch);                     // 运行cURL,请求URL,把结果复制给变量
if(curl_errno($ch)){
    echo 'Errno'.curl_error($ch);         //捕抓异常
}
curl_close($ch);                            // 关闭cURL连接
$preg = preg_replace("/\s/",'',$html);
preg_match_all('/<tr><td>(.*)<\/td><td>(.*)<\/td><\/tr>/Usi',$preg,$match);
$info = array_combine($match[1],$match[2]);
print_r($info);

2、创建分类表

Navicat for MySQL 数据库软件
CREATE TABLE `baidu_cat` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
    `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父ID',
    `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '分类名',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、pdo.php 公共文件

<?php

/**
 * 数据库连接
 * @param $db
 * @return PDO
 */
function connect()
{
    $db = array(
        'charset' => 'utf8',
        'port' => 3306,
        'type' => 'mysql',
        'host' => '127.0.0.1',
        'user' => 'root',
        'pass' => 'root',
        'name' => 'ouyangke'
    );
    $dsn = "{$db['type']}:host={$db['host']}; dbname={$db['name']}; charset={$db['charset']}; port={$db['port']}"; //数据源
    try {
        //实例化PDO类,创建PDO对象
        $pdo = new PDO($dsn, $db['user'], $db['pass']);
    } catch (PDOException $e) {
        die('数据库错误:' . $e->getMessage());
    }
    return $pdo;
}
/**
 * 查询多条记录
 * @param $db
 * @param $table
 * @param $fields
 * @param string $where
 * @return array
 */
function select($table, $fields, $where = '', $order = '', $limit = '')
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql = 'SELECT ';
    if (is_array($fields)) {
        foreach ($fields as $field) {
            $sql .= $field . ', ';
        }
    } else {
        $sql .= $fields;
    }
    $sql = rtrim(trim($sql), ',');
    $sql .= '  FROM ' . $table;
    //查询条件
    if (!empty($where)) {
        if (is_array($where)) {
            $sql .= ' WHERE ';
            foreach ($where as $k => $v) {
                $sql .= '`' . $k . '`="' . $v . '" AND ';
            }
            $sql = substr($sql, 0, strlen($sql) - 5);
        } else {
            $sql .= ' WHERE ' . $where;
        }
    }
    //排序条件
    if (!empty($order)) {
        $sql .= ' order by ' . $order;
    }
    //分页条件
    if (!empty($limit)) {
        $sql .= ' limit ' . $limit;
    }
    $sql .= ';';
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行查询操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            $stmt->setFetchMode(PDO::FETCH_ASSOC);
            //返回一个二维数组
            return $stmt->fetchAll();
        }
    } else {
        return false;
    }
}
/**
 * 查询单条记录
 * @param $db
 * @param $table   表名
 * @param $fields  返回值 *
 * @param string $where  条件
 * @return array
 */
function find($table, $fields, $where = '')
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql = 'SELECT ';
    if (is_array($fields)) {
        foreach ($fields as $field) {
            $sql .= $field . ', ';
        }
    } else {
        $sql .= $fields;
    }
    $sql = rtrim(trim($sql), ',');
    $sql .= ' FROM ' . $table;
    //查询条件
    if (!empty($where)) {
        if (is_array($where)) {
            $sql .= ' WHERE ';
            foreach ($where as $k => $v) {
                $sql .= '`' . $k . '`="' . $v . '" AND ';
            }
            $sql = substr($sql, 0, strlen($sql) - 5);
        } else {
            $sql .= ' WHERE ' . $where;
        }
    }
    $sql .= ' LIMIT 1;';
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行查询操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            $stmt->setFetchMode(PDO::FETCH_ASSOC);
            return $stmt->fetch();
        }
    } else {
        return false;
    }
}
/**
 * 新增数据
 * @param $db
 * @param $table
 * @param $data
 * @return bool
 */
function insert($table, $data = [])
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql = "INSERT INTO {$table} SET ";
    //组装插入语句
    if (is_array($data)) {
        foreach ($data as $k => $v) {
            $sql .= $k . '="' . $v . '", ';
        }
    } else {
        return false;
    }
    //去掉尾部逗号,并添加分号结束
    $sql = rtrim(trim($sql), ',') . ';';
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行新增操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            return true;
        }
    } else {
        return false;
    }
}
/**
 * 新增数据,返回新增ID
 * @param $db
 * @param $table
 * @param $data
 * @return bool
 */
function insertId($table, $data = [])
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql = "INSERT INTO {$table} SET ";
    //组装插入语句
    if (is_array($data)) {
        foreach ($data as $k => $v) {
            $sql .= $k . '="' . $v . '", ';
        }
    } else {
        return false;
    }
    //去掉尾部逗号,并添加分号结束
    $sql = rtrim(trim($sql), ',') . ';';
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行新增操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            return $pdo->lastInsertId();
        }
    } else {
        return false;
    }
}
/**
 * 更新数据
 * @param $db
 * @param $table
 * @param $data
 * @return bool
 */
function update($table, $data = [], $where = '')
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql = "UPDATE {$table} SET ";
    //组装修改语句
    if (is_array($data)) {
        foreach ($data as $k => $v) {
            $sql .= $k . '="' . $v . '", ';
        }
    }
    //去掉尾部逗号,并添加分号结束
    $sql = rtrim(trim($sql), ',');
    //查询条件
    if (!empty($where)) {
        $sql .= ' WHERE ' . $where;
    }
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行新增操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            return true;
        }
    } else {
        return false;
    }
}
/**
 * 删除记录
 * @param $db
 * @param $table
 * @param string $where
 * @return bool
 */
function delete($table, $where = '')
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql = "DELETE FROM {$table}  ";
    //查询条件
    if (!empty($where)) {
        $sql .= ' WHERE ' . $where;
    }
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行删除操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            return true;
        }
    } else {
        return false;
    }
}
/**
 * 统计数量
 * @param $pdo
 * @param $table
 * @param string $where
 * @return number
 */
function count_num($table, $where)
{
    //连接pdo
    $pdo = connect();
    //创建SQL语句
    $sql  = 'SELECT count(*) as count_number FROM ' . $table;
    //查询条件
    if (!empty($where)) {
        $sql .= ' WHERE ' . $where;
    }
    //创建PDO预处理对象
    $stmt = $pdo->prepare($sql);
    //执行查询操作
    if ($stmt->execute()) {
        if ($stmt->rowCount() > 0) {
            $row  = $stmt->fetch(PDO::FETCH_ASSOC);
            $rows = $row['count_number'];
            return $rows;
        }
    } else {
        return false;
    }
}

4、保存分类

引入pdo公用文件

require 'pdo.php';

循环获取到的数据

foreach ($info as $k => $v) {
    # 整理数据
    $data = [
        'name' => $k
    ];
    # 插入一级分类
    $id = insertId('baidu_cat',$data);
    # 分割二级分类
    $two = explode('、', $v);
    # 循环二级分类
    foreach($two as $kk => $vv){
        # 整理数据
        $data = [
            'pid' => $id,
            'name' => $vv
        ];
        # 插入二级分类
        $insert = insert('baidu_cat',$data);
    }
}
echo '抓取成功';

5、逻辑

引入pdo公用文件

require 'pdo.php';

循环获取到的数据

foreach ($info as $k => $v) {
    # 整理数据
    $data = [
        'name' => $k
    ];
    # 查询一级分类是否存在
    $find = find('baidu_cat','*',$data);
    if(empty($find)){
        # 插入一级分类
        $id = insertId('baidu_cat',$data);
    }else{
        $id = $find['id'];
    }
    # 分割二级分类
    $two = explode('、', $v);
    # 循环二级分类
    foreach($two as $kk => $vv){
        # 整理数据
        $data = [
            'pid' => $id,
            'name' => $vv
        ];
        # 查询二级分类是否存在
        $find = find('baidu_cat','*',$data);
        if(empty($find)){
            # 插入二级分类
            $insert = insert('baidu_cat',$data);
        }
    }
}
echo '抓取成功';

6、日志

引入pdo公用文件

require 'pdo.php';

日志变量

$msg = '';
foreach ($info as $k => $v) {
    # 整理数据
    $data = [
        'name' => $k
    ];
    $find = find('baidu_cat','*',$data);
    # 查询一级分类是否存在
    if(empty($find)){
        # 插入一级分类
        $id = insertId('baidu_cat',$data);
        # 一级分类添加成功记录
        $msg .= '<span style="color:green;">一级分类已添加,ID:'.$id.',分类名:'.$k.'</span><br/>';
    }else{
        # 获取已存在的分类ID
        $id = $find['id'];
        # 一级分类添加失败记录
        $msg .= '<span style="color:red;">一级分类已存在,ID:'.$id.',分类名:'.$k.'</span><br/>';
    }
    # 分割二级分类
    $two = explode('、', $v);
    # 循环二级分类
    foreach($two as $kk => $vv){
        # 整理数据
        $data = [
            'pid' => $id,
            'name' => $vv
        ];
        # 查询二级分类是否存在
        $find = find('baidu_cat','*',$data);
        if(empty($find)){
            # 插入二级分类
            $insert = insertId('baidu_cat',$data);
            # 二级分类添加成功记录
            $msg .= '<span style="color:green;">二级分类已添加,ID:'.$insert.',分类名:'.$vv.'</span><br/>';
        }else{
            # 二级分类添加失败记录
            $msg .= '<span style="color:red;">二级分类已存在,ID:'.$find['id'].',分类名:'.$vv.'</span><br/>';
        }

    }
}
echo $msg;

二、抓取百度商家

key:u9WcDUIQLqFX3D8vNfN3hvAFiXGYueAv
文档:https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi

1、获取数据

header("Content-Type:text/html;charset=utf8");
$url = 'https://api.map.baidu.com/place/v2/search?ak=1PQvdVNrRaLeCbkVB9VbZoQ9RyGFy7Kq&scope=2&output=json&query=美食&region=合肥&page_size=20&page_num=1';

$ch = curl_init();                          // 创建一个新cURL资源
curl_setopt($ch, CURLOPT_URL, $url);        // 设置URL
curl_setopt($ch, CURLOPT_TIMEOUT, 30);      // 设置超时限制防止死循环
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// 爬取重定向页面
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);   // 自动设置Referer,防止盗链
curl_setopt($ch, CURLOPT_HEADER, 0);        // 显示返回的Header区域内容
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);// 要求结果保存到字符串中还是输出到屏幕上
curl_setopt($ch, CURLOPT_USERAGENT, 'Data');// 在HTTP请求中包含一个"User-Agent: "头的字符串。

$html = curl_exec($ch);                     // 运行cURL,请求URL,把结果复制给变量
if(curl_errno($ch)){
    echo 'Errno'.curl_error($ch);         //捕抓异常
}
curl_close($ch);                            // 关闭cURL连接
print_r($html);

2、数据库

CREATE TABLE `baidu_shop` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
    `name` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '店铺名',
    `province` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '省',
    `city` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '市',
    `area` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '区',
    `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地址',
    `telephone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '店铺电话',
    `tag` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '分类',
    `detail_url` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '来源url',
    `lng` decimal(10,6) DEFAULT NULL COMMENT '经度',
    `lat` decimal(10,6) DEFAULT NULL COMMENT '纬度',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、存入数据

引入pdo公用文件

require 'pdo.php';

判断是否有数据

if(!empty($html['results'])){
    # 循环获取到的数据
    foreach ($html['results'] as $k => $v) {
        # 整理数据
        $data = [
            'name' => $v['name'],
            'province' => $v['province'],
            'city' => $v['city'],
            'area' => $v['area'],
            'address' => $v['address'],
            'telephone' => $v['telephone'],
            'tag' => $v['detail_info']['tag'],
            'detail_url' => $v['detail_info']['detail_url'],
            'lng' => $v['location']['lng'],
            'lat' => $v['location']['lat']
        ];
        # 插入数据
        $id = insertId('baidu_shop',$data);
    }
}
echo '抓取成功';

4、逻辑、日志

引入pdo公用文件

require 'pdo.php';

日志变量

$msg = '';
# 判断是否有数据
if(!empty($html['results'])){
    # 循环获取到的数据
    foreach ($html['results'] as $k => $v) {
        # 判断经纬度是否存在
        $find = find('baidu_shop','*',['lng'=>$v['location']['lng'],'lat'=>$v['location']['lat']]);
        # 如果存在,跳出这一次循环,并记录
        if($find){
            $msg .= '<span style="color:red;">'.$v['name'].'已存在,ID为:'.$find['id'].'</span><br/>';
            continue;
        }
        # 整理数据
        $data = [
            'name' => $v['name'],
            'province' => $v['province'],
            'city' => $v['city'],
            'area' => $v['area'],
            'address' => $v['address'],
            'telephone' => $v['telephone'],
            'tag' => $v['detail_info']['tag'],
            'detail_url' => $v['detail_info']['detail_url'],
            'lng' => $v['location']['lng'],
            'lat' => $v['location']['lat']
        ];
        # 插入数据
        $id = insertId('baidu_shop',$data);
        # 插入成功记录
        if($id){
            $msg .= '<span style="color:green;">'.$v['name'].'添加成功,ID为:'.$id.'</span><br/>';
        }else{
            $msg .= '<span style="color:red;">'.$v['name'].'添加失败</span><br/>';
        }
    }
}
echo $msg;

5、分类处理

增加 2 个字段,存储分类
ALTER TABLE `baidu_shop`
ADD COLUMN `cat_one` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '一级分类' AFTER `lat`,
ADD COLUMN `cat_two` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '二级分类' AFTER `cat_one`;

循环获取到的数据

foreach ($html['results'] as $k => $v) {
    # 判断经纬度是否存在
    $find = find('baidu_shop','*',['lng'=>$v['location']['lng'],'lat'=>$v['location']['lat']]);
    # 如果存在,跳出这一次循环,并记录
    if($find){
        $msg .= '<span style="color:red;">'.$v['name'].'已存在,ID为:'.$find['id'].'</span><br/>';
        continue;
    }
    # 分割 获取标签
    $tag = explode(';',$v['detail_info']['tag']);
    # 获取一级分类ID
    $cat_one = find('baidu_cat','*',['name'=>$tag[0]]);
    # 获取二级分类ID
    $cat_two = find('baidu_cat','*',['name'=>$tag[1]]);
    # 整理数据
    $data = [
        'name' => $v['name'],
        'province' => $v['province'],
        'city' => $v['city'],
        'area' => $v['area'],
        'address' => $v['address'],
        'telephone' => isset($v['telephone'])?$v['telephone']:'',
        'tag' => $v['detail_info']['tag'],
        'detail_url' => $v['detail_info']['detail_url'],
        'lng' => $v['location']['lng'],
        'lat' => $v['location']['lat'],
        'cat_one' => isset($cat_one['id'])?$cat_one['id']:0,
        'cat_two' => isset($cat_two['id'])?$cat_two['id']:0
    ];
    # 插入数据
    $id = insertId('baidu_shop',$data);
    # 插入成功记录
    if($id){
        $msg .= '<span style="color:green;">'.$v['name'].'添加成功,ID为:'.$id.'</span><br/>';
    }else{
        $msg .= '<span style="color:red;">'.$v['name'].'添加失败</span><br/>';
    }
}

6、传值

header("Content-Type:text/html;charset=utf8");
$p = isset($_GET['p'])?$_GET['p']:1;
$url = 'https://api.map.baidu.com/place/v2/search?ak=1PQvdVNrRaLeCbkVB9VbZoQ9RyGFy7Kq&scope=2&output=json&query=美食&region=合肥&page_size=20&page_num='.$p;
备:我们使用网页可以执行,使用其他的请求方法 也能执行。但我们更需要自动执行

7、curl_ssl相关参数设置

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);      // 设置为 1 是检查服务器SSL证书中是否存在一个公用名(common name)。译者注:公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)。 设置成 2,会检查公用名是否存在,并且是否与提供的主机名匹配。 0 为不检查名称。 在生产环境中,这个值应该是 2(默认值)。
curl_setopt($ch, CURLOPT_SSL_FALSESTART, false);      // true 开启 TLS False Start (一种 TLS 握手优化方式) 
curl_setopt($ch, CURLOPT_SSL_ENABLE_ALPN, false);      // false 禁用 SSL 握手中的 ALPN (如果 SSL 后端的 libcurl 内建支持) 用于协商到 http2。 
curl_setopt($ch, CURLOPT_SSL_ENABLE_NPN, false);      // false 禁用 SSL 握手中的 NPN(如果 SSL 后端的 libcurl 内建支持),用于协商到 http2。
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);      // false 禁止 cURL 验证对等证书(peer's certificate)。要验证的交换证书可以在 CURLOPT_CAINFO 选项中设置,或在 CURLOPT_CAPATH中设置证书目录。 
curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, false);      // true 验证证书状态。 
最后修改:2023 年 01 月 15 日
如果觉得我的文章对你有用,请随意赞赏