/**
* _ooOoo_
* o8888888o
* 88" . "88
* (| -_- |)
* O\ = /O
* ____/`---'\____
* .' \\| |// `.
* / \\||| : |||// \
* / _||||| -:- |||||- \
* | | \\\ - /// | |
* | \_| ''\---/'' | |
* \ .-\__ `-` ___/-. /
* ___`. .' /--.--\ `. . __
* ."" '< `.___\__/___.' >'"".
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
* \ \ `-. \_ __\ /__ _/ .-` / /
* ======`-.____`-.___\_____/___.-`____.-'======
* `=---='
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* 佛祖保佑 永无BUG
*/
require 'vendor/autoload.php';
use Medoo\Medoo;
use QL\QueryList;
// 生成一个querylist对象
$ql = new QueryList();
// 生成一个medoo数据库对象
$database = new Medoo([
'database_type' => 'mysql',
'database_name' => 'bookstore',
'server' => 'localhost',
'username' => 'root',
'password' => 'root',
'charset' => 'utf8',
]);
/*
* @Description:获取分类
* @params: 主页url
* @return: 二维数组, 包括分类名称, 分类url
*/
function get_category($url){
global $ql;
$data = $ql->get($url)->rules([
"category_name" => ['#default > div > div > div > aside > div.side_categories > ul > li > ul > li > a', 'text'],
"category_url" => ['#default > div > div > div > aside > div.side_categories > ul > li > ul > li > a', 'href'],
])->queryData();
// 把分类的链接地址补全
foreach ($data as $key => $value) {
$value['category_url'] = $url . $value['category_url'];
$data[$key] = $value;
}
return $data;
}
/*
* @Description: 获取分类下的图书信息, 如果有下一页, 递归获取
* @param: 分类的url
* @return: 二维数组, 包括图书名称, 图书价格
*/
function get_book($url){
global $ql;
echo $url . "\n";
$data = $ql->get($url)->rules([
"book_name" => ['#default > div > div > div > div > section > div:nth-child(2) > ol > li > article > h3 > a', 'title'],
"book_price" => ['#default > div > div > div > div > section > div:nth-child(2) > ol > li> article > div.product_price > p.price_color', 'text'],
])->queryData();
// 获取下一页按钮的href, 用来拼接下一页的完整url
$next = has_next($url);
if ($next) {
// 生成完整url
$tmp_arr = explode('/', $url);
$tmp_arr[count($tmp_arr) - 1] = $next;
$next_url = implode('/', $tmp_arr);
// 调用get_book(), 把返回的数据和当前数据合并
$data = array_merge($data, get_book($next_url));
}
return $data;
}
/*
* @Description: 判断有没有下一页
* @param: 当前url
* @return: 如果有返回按钮的href, 如果没有, 返回空字符串
*/
function has_next($url){
global $ql;
$res = $ql->get($url)->find('#default > div > div > div > div > section > div:nth-child(2) > div > ul > li.next > a')->href;
return $res;
}
/*
* @Description: 生成最终的数组
* @param: 从分类获取的数组
* @return: 最终整合了图书信息的数组
*/
function make_array($data){
foreach ($data as $key => $value) {
$value['books'] = get_book($value['category_url']);
$data[$key] = $value;
}
return $data;
}
/*
* @Description: 把整合好的数据, 写入数据库
* @param: 整合好的数组
* @return: 没有返回值
*/
function save_data($data){
foreach ($data as $key => $value) {
$bcid = create_category($value['category_name']);
foreach ($value['books'] as $k => $book) {
$bname = $book['book_name'];
$bprice = $book['book_price'];
create_book($bname, $bprice, $bcid);
}
}
}
/*
* @Description:往类别表里插入数据
* @param: 类别名称
* @return: 没有返回值
*/
function create_category($category_name){
global $database;
$id = $database->insert('category', [
'cname' => $category_name
]);
return $database->id();
}
/*
* @Description: 往图书表中插入数据
* @param: 图书名称
* @param: 图书价格
* @param: 图书的分类id
* @return: 没有返回值
*/
function create_book($bname, $bprice, $bcid){
global $database;
$database->insert('book', [
'bname' => $bname,
'bprice' => $bprice,
'bcid' => $bcid,
]);
}
// 爬取并整合数据
$data = make_array(get_category('http://books.toscrape.com/'));
// 把数据写入books.txt
save_data($data);
复制代码