示例
一、抓取百度分类
文档: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=美食®ion=合肥&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=美食®ion=合肥&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 验证证书状态。