PHP爬虫 -- 010 作业解析

622 阅读2分钟

作业回顾

  • 爬取分类下的图书名和对应价格, 保存到books.txt
  • books.toscrape.com
  • 最终效果...

作业解析

  • 两个难度
  • 简单难度
    • 爬取分类和分类下的第一页的数据, 不包括分页
    • 所需要的知识已经讲过, 不需要额外的知识
  • 中等难度
    • 爬取分类和分类下的所有数据, 需要判断总页数
    • 需要额外的知识, 字符串切割/截取

作业分析

  1. 先获取分类的名称和url
  2. 再通过url获取分类下的图书信息
  3. 注意分类的url需要拼接

小彩蛋: 运行前清屏

代码解析-简单难度-带注释

<?php


/**
 *                             _ooOoo_
 *                            o8888888o
 *                            88" . "88
 *                            (| -_- |)
 *                            O\  =  /O
 *                         ____/`---'\____
 *                       .'  \\|     |//  `.
 *                      /  \\|||  :  |||//  \
 *                     /  _||||| -:- |||||-  \
 *                     |   | \\\  -  /// |   |
 *                     | \_|  ''\---/''  |   |
 *                     \  .-\__  `-`  ___/-. /
 *                   ___`. .'  /--.--\  `. . __
 *                ."" '<  `.___\_<|>_/___.'  >'"".
 *               | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *               \  \ `-.   \_ __\ /__ _/   .-` /  /
 *          ======`-.____`-.___\_____/___.-`____.-'======
 *                             `=---='
 *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *                     佛祖保佑        永无BUG
*/

require 'vendor/autoload.php';
use QL\QueryList;
// 生成一个querylist对象
$ql = new QueryList();

/*
 * @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;

    $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();

    return $data;

}

/*
 * @Description: 生成最终的数组
 * @param: 从分类获取的数组
 * @return: 最终整合了图书信息的数组
 */
function make_array($data)
{
    foreach ($data as $key => $value) {
        echo $value['category_url']."\n";
        $value['books'] = get_book($value['category_url']);
        $data[$key] = $value;
    }
    return $data;
}
/* 
 * @Description: 写入txt文件
 * @param: 整合好的数组
 * @return: 没有返回值
*/ 
function make_txt($data)
{
    $txt_obj = fopen('books.txt', 'w+');
    foreach ($data as $key => $value) {
        $category_name = $value['category_name'];
        fwrite($txt_obj, "{$category_name}\n");
        foreach ($value['books'] as $k => $book) {
            $book_name = $book['book_name'];
            $book_price = $book['book_price'];
            fwrite($txt_obj, "\t\"{$book_name}\" {$book_price}\n");
        }
    }
    fclose($txt_obj);
}


// 爬取并整合数据
$data = make_array(get_category('http://books.toscrape.com/'));
// 把数据写入books.txt
make_txt($data);

代码解析-中等难度-带注释

<?php


/**
 *                             _ooOoo_
 *                            o8888888o
 *                            88" . "88
 *                            (| -_- |)
 *                            O\  =  /O
 *                         ____/`---'\____
 *                       .'  \\|     |//  `.
 *                      /  \\|||  :  |||//  \
 *                     /  _||||| -:- |||||-  \
 *                     |   | \\\  -  /// |   |
 *                     | \_|  ''\---/''  |   |
 *                     \  .-\__  `-`  ___/-. /
 *                   ___`. .'  /--.--\  `. . __
 *                ."" '<  `.___\_<|>_/___.'  >'"".
 *               | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *               \  \ `-.   \_ __\ /__ _/   .-` /  /
 *          ======`-.____`-.___\_____/___.-`____.-'======
 *                             `=---='
 *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *                     佛祖保佑        永无BUG
*/

require 'vendor/autoload.php';
use QL\QueryList;
// 生成一个querylist对象
$ql = new QueryList();

/*
 * @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) {
        echo $value['category_url']."\n";
        $value['books'] = get_book($value['category_url']);
        $data[$key] = $value;
    }
    return $data;
}
/* 
 * @Description: 写入txt文件
 * @param: 整合好的数组
 * @return: 没有返回值
*/ 
function make_txt($data)
{
    $txt_obj = fopen('books.txt', 'w+');
    foreach ($data as $key => $value) {
        $category_name = $value['category_name'];
        fwrite($txt_obj, "{$category_name}\n");
        foreach ($value['books'] as $k => $book) {
            $book_name = $book['book_name'];
            $book_price = $book['book_price'];
            fwrite($txt_obj, "\t\"{$book_name}\" {$book_price}\n");
        }
    }
    fclose($txt_obj);
}


// 爬取并整合数据
$data = make_array(get_category('http://books.toscrape.com/'));
// 把数据写入books.txt
make_txt($data);

下一节