亲宝软件园·资讯

展开

PHP爬虫-爬取接口篇

Fang20 人气:0

爬虫其实是用程序向对方服务器发出HTTP请求,从而获得想要的信息。

所以用PHP脚本完全可以进行一些简单的爬虫。

练习需求

这里我拿某网站酒店列表做技术练习,需求是获取网站上酒店列表数据。

观察

首先需要观察网站是怎么获取数据的,在浏览器打开网站后 按F12 打开调试窗口,再打开network 或者 网络 Tab栏。

打开后 尝试 F5 刷新页面,查看网站的请求日志。

 在网络栏能很清楚看到分别在什么时候请求了哪些接口。

 查看每个接口根据返回的内容找到需要的接口,找到需要的接口后开始分析请求头。

 主要是看请求的 URL地址,请求类型,客户端向服务器传了哪些参数以及请求头的其它内容。

Postman验证观察

大概知道网站是如何获取信息后,可以通过 Postman软件 先验证观察。(Postman是免费软件,可以自行下载安装)

 

通过 Postman 可以试图删除或修改传递的参数,通过返回内容最大化理解接口参数代表的含义。

通过修改几个请求参数,看返回值的返回情况,大致能知道接口用法。

PHP模拟请求

一般网站一部分数据是开放给游客的,一部分数据可能需要登陆才能查看。这里只是获取开放的列表数据,所以登陆部分暂不考虑,这也大大减低了难度。(登陆可能会碰到各类人机验证)

 根据上文的操作,分析发现在页面操作的搜索条件会生成一个带参数的URL,根据URL里的参数可以提取出部分请求参数。

 所以第一步是解析URL里的参数,我为了方便开发新建了一个工具类。

<?php


class Util
{
    public function curl($url, $data, $isPost = true, $header = [])
    {
        $ch = curl_init();

        if (!empty($data) && $isPost) {
            if (is_array($data)) {
                $data = json_encode($data);
            }
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }

        if (!$isPost) {
            $url .= "?" . http_build_query($data);
        }

        curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_POST, $isPost);
        curl_setopt($ch, CURLOPT_TIMEOUT,5);
        if (stripos($url, "https") !== false) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }

        if (!empty($header)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        }


        $content = curl_exec($ch);
        curl_close($ch);
        return $content;
    }


    public function getCtripParamByUrl($url)
    {
        $urlZh = urldecode($url);
        $pattern = '/(\?|&)(.+?)=([^&?]*)/i';
        $param = [];
        preg_match_all($pattern, $urlZh, $param);

        $indexParam = [];
        foreach ($param[2] as $key => $item){
            $item = str_replace('&','', $item);
            $indexParam[$item] = $param[3][$key];
        }

        return $indexParam;
    }
}

剩下来就很简单了,主要是将URL获取的参数拼凑成请求接口的参数,并通过工具类的curl方法去请求服务器。

    public function getHotelListByUrl($url, $page = 1, $pageSize = 60)
    {
        $param = $this->util->getCtripParamByUrl($url);
        $requestParam = $this->requestParam;

        $requestParam['searchCondition']['countryId'] = (int)$param['countryId'];
        $requestParam['searchCondition']['cityId'] = (int)$param['city'];
        $requestParam['searchCondition']['optionId'] = (string)$param['optionId'];
        $requestParam['searchCondition']['optionType'] = (string)$param['optionType'];
        $requestParam['searchCondition']['directSearch'] = (int)$param['directSearch'];
        $requestParam['searchCondition']['adult'] = (int)$param['adult'];
        $requestParam['searchCondition']['travelPurpose'] = (int)$param['travelPurpose'];
        $requestParam['searchCondition']['sortType'] = (string)$param['sort'];
        $requestParam['searchCondition']['child'] = (int)$param['children'];

        $startDate = date('Y-m-d', strtotime($param['checkin']));
        $endDate = date('Y-m-d', strtotime($param['checkout']));

        $requestParam['searchCondition']['checkIn'] = $startDate;
        $requestParam['searchCondition']['checkOut'] = $endDate;
        $requestParam['genKeyParam']['b'] = $startDate;
        $requestParam['genKeyParam']['c'] = $endDate;

        $requestParam['searchCondition']['url'] = $url;
        $requestParam['searchCondition']['pageSize'] = $pageSize;
        $requestParam['searchCondition']['pageNo'] = $page;

        $cityParam = explode(',', $param['display']);
        $requestParam['searchCondition']['cityName'] = current($cityParam);

//        $requestParam['filterCondition']['zone'] = [$param['zone']];
        $requestParam['filterCondition']['priceRange'] = [
            'lowPrice'  => $param['lowPrice'] ?: -1,
            'highPrice' => $param['highPrice'] ?: -1
        ];

        $listUrl = 'https://m.ctrip.com/restapi/soa2/16709/json/HotelSearch';
        $header = [
            'Accept: */*',
            'Cache-Control: no-cache',
            'User-Agent: spider',
            'Accept-Encoding: gzip, deflate, br',
            'Connection: keep-alive',
            'Content-Type: application/json;charset=UTF-8',
        ];
        $content = $this->util->curl($listUrl, $requestParam, true, $header);
        $value = json_decode($content, true);
        if (isset($value['Response']['hotelList'])) {
            $list = $value['Response']['hotelList']['list'];
            $resultTitle = $value['Response']['resultTitle'];
            preg_match_all('/\d+/',$resultTitle,$totalArr);
            return [
                'list' => $list,
                'total' => join(current($totalArr))
            ];
        }else{
            return false;
        }
    }

在写个场景方法去调用测试一下:

 

 经过一系列修正传过去的参数,最后成功调用接口并拿到了列表数据。

 可以获取列表数据后,写个场景方法去循环调用获取信息,再根据需要将数据保存到数据库或者其它地方即可,这里我只是将数据存在本地的文本文件中。

 

 至此一个简单的接口爬虫就结束了,我把代码上传到 码云 方便交流。

小结

1. 分析目标网页;

2. 借助浏览器开发者工具以及Postman模拟请求测试;

3. 编写代码循环请求。

加载全部内容

相关教程
猜你喜欢
用户评论