从零开始,学会 PHP 采集

mengkun 30K 49

今天通过两个具体的实例,教大家从零开始使用 PHP 来抓取需要的数据。

准备工作

首先,你需要准备一个 Html 编辑器(如 notepad++),以及一个支持 PHP 的网站空间。

新建一个 PHP 文件,命名为 get.php

第一行代码

打开 get.php ,在里面输入

  1. <?php
  2. echo 'hello php';
  3. ?>

保存,然后将这个 PHP 文件上传至你的网站空间,通过浏览器访问这个 PHP 文件,浏览器输出 “hello php”。恭喜你!已经写下了第一行 PHP 代码!

别看只有小小的三行代码,其实包含了很多知识点!(敲黑板……)

第一行代码的 尖括号+问号+php 是 PHP 语言的开始标记,所有的 PHP 代码都要写在开始标记的后面。

第二行代码是一个输出语句,用 echo 输出一个字符串。字符串用单引号包起来。其实用双引号也是一样的。双引号与单引号的区别是双引号中可以直接放变量。每一句 PHP 代码的结尾都用半角的分号表示结束。

第三行的 问号+反尖括号 是 PHP 的结束标记,用于表示 PHP 代码到这里就全部结束了。如果后面没有了其它的 HTML 代码,那么结束标记可以省略

初试信息抓取

以下内容以抓取 图灵机器人 的 Api 接口内容为例:

图灵机器人 提供了一个虚拟聊天机器人数据接口,它的调用方式如下:

  1. http://www.tuling123.com/openapi/api?key=e825286159f9f57db1b597995d72ae2b&info=你要说的话

我们可以直接在浏览器中访问这个接口地址。浏览器会显示如下内容:

  1. {"code":100000,"text":"我有话要对谁说呢"}

这种用大括号括起来的数据格式叫 JSON。待会我们再谈如何去解析 JSON 数据。

现在我们要做的是通过 PHP 来抓取上述接口的内容。

PHP 有一个很方便的文件读取函数:file_get_contents()。我们可以直接用 file_get_contents('要抓取的网址') 来获取指定网址(接口)的内容

代码示例:

  1. <?php
  2. $data = file_get_contents('http://www.tuling123.com/openapi/api?key=e825286159f9f57db1b597995d72ae2b&info=你好');
  3. echo $data;
  4. ?>

运行这行代码,浏览器中显示的应该是和直接去访问原接口地址类似的内容。这就说明我们已经成功地从图灵的接口抓取到了数据。

JSON 数据的解析

下面,我们需要从原始的 JSON 中解析出 "text" 这个键值的内容,也就是机器人回复你的内容。

同样的,PHP 也提供了一个非常方便的用于解析 JSON 的函数:json_decode()。这个函数有两个参数,第一个参数是原始 JSON 数据,第二个参数 assoc 用于指定返回数据的格式,如果为 true 返回数组格式,如果为 false 则返回一个对象。

我们这里将 JSON 解析成数组来使用。

代码如下:

  1. <?php
  2. $data = file_get_contents('http://www.tuling123.com/openapi/api?key=e825286159f9f57db1b597995d72ae2b&info=你好');    // 从图灵的接口获取数据
  3. $arr = json_decode($data, true);    // 将获取到的 JSON 数据解析成数组
  4. echo $arr['text'];        // 输出数组中的 “text” 值(也就是之前 JSON 中的“text”键值中的内容)
  5. ?>

现在我们去运行代码,浏览器中只会显示机器人回复的内容了,没有了其它的 json 内容。

参数获取

上面的代码中,接口中发送的字符串(也就是我们发给机器人)的文字是固定的,如果要给机器人发不同的内容,那么只能修改代码……这样很不方便。

其实,我们可以通过 get 的方式传递给 PHP 一些参数,以此来动态改变内容。

PHP 中可以使用 $_GET() 来获取 get 方式发送的数据。

那么问题来了,什么是 get 发送数据呢?仔细研究一下图灵的接口,它的数据传递方式是 图灵接口+你要说的话 这种数据传送方式就是 get。你如果直接在浏览器里访问可以在地址栏看到全部的 get 发送的数据。

加了 get 数据传递后的代码如下:

  1. <?php
  2. $get = $_GET['says'];    // 获取 get 数据
  3. $data = file_get_contents('http://www.tuling123.com/openapi/api?key=e825286159f9f57db1b597995d72ae2b&info='.$get);    // 从图灵的接口获取数据
  4. $arr = json_decode($data, true);    // 将获取到的数据解析成 JSON 格式
  5. echo $arr['text'];        // 输出数组中的 “text” 值(也就是之前 JSON 中的“text”键值中的内容)
  6. ?>

现在,你可以直接跟你的机器人“对话”了。

方法就是访问

  1. http://你的网址/get.php?says=你想说的话

至此,你已经学会了抓取 Api 接口的内容并解析 JSON 数据。

但是有时我们抓取到的数据格式并不是 JSON,那该怎么办呢?且听我慢慢说来……

初识 Curl

上面介绍了一个抓取网页数据的 PHP 函数:file_get_contents() ,这个函数使用起来非常简单,但却不是万能的。

下面以 126 的 IP 定位接口为例:

  1. http://ip.ws.126.net/ipquery  

直接访问这个接口地址,你会发现浏览器返回了你当前的 省份 和 城市 信息。

我们再尝试用 file_get_contents() 来抓取这个接口的内容。

  1. <?php  
  2. $data = file_get_contents('http://ip.ws.126.net/ipquery');    // 从接口获取数据  
  3. echo $data;  
  4. ?>  

运行这行代码,你会发现浏览器中输出的并不是你本地的地址,而是服务器的地址。

你用 PHP 从服务器去抓取,接口那边获取到的是你服务器的 IP,然后返回服务器的地址,没毛病!

那么,可不可以在服务器那边伪造一个 IP 地址,然后去抓取呢?

当然可以~这时就得是 Curl 上场了。Curl 的参数有很多,用法也很复杂。具体的可以百度去了解。我这里直接提供一个封装好的函数,可以拿来直接使用。

  1. /** 
  2.  * Curl 伪造 IP 并从指定网址获取数据 
  3.  * @param $url 接口地址 
  4.  * @param $ip 伪造的 IP 
  5.  * @return 抓取到的内容 
  6.  */  
  7. function myCurl($url$ip){   
  8.     $ch = curl_init();     // Curl 初始化  
  9.     $timeout = 30;     // 超时时间:30s  
  10.     $ua='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36';    // 伪造抓取 UA  
  11.     curl_setopt($ch, CURLOPT_URL, $url);              // 设置 Curl 目标  
  12.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);      // Curl 请求有返回的值  
  13.     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);     // 设置抓取超时时间  
  14.     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);        // 跟踪重定向  
  15.     curl_setopt($ch, CURLOPT_ENCODING, "");    // 设置编码  
  16.     curl_setopt($ch, CURLOPT_REFERER, $url);   // 伪造来源网址  
  17.     curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:'.$ip, 'CLIENT-IP:'.$ip));  //伪造IP  
  18.     curl_setopt($ch, CURLOPT_USERAGENT, $ua);   // 伪造ua   
  19.     curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // 取消gzip压缩  
  20.     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts  
  21.     curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);  
  22.     $content = curl_exec($ch);   
  23.     curl_close($ch);    // 结束 Curl  
  24.     return $content;    // 函数返回内容  
  25. }  

有了这个函数你就可以直接通过 myCurl('目标网址', '伪造的IP') 来伪造 IP 并获取数据了。

示例如下:

  1. <?php  
  2. $data = myCurl('http://ip.ws.126.net/ipquery', '223.81.141.38');    // 伪造 IP 并获取数据  
  3. echo $data;  
  4.   
  5. /** 
  6.  * Curl 伪造 IP 并从指定网址获取数据 
  7.  * @param $url 接口地址 
  8.  * @param $ip 伪造的 IP 
  9.  * @return 抓取到的内容 
  10.  */  
  11. function myCurl($url$ip){   
  12.     $ch = curl_init();     // Curl 初始化  
  13.     $timeout = 30;     // 超时时间:30s  
  14.     $ua='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36';    // 伪造抓取 UA  
  15.     curl_setopt($ch, CURLOPT_URL, $url);              // 设置 Curl 目标  
  16.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);      // Curl 请求有返回的值  
  17.     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);     // 设置抓取超时时间  
  18.     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);        // 跟踪重定向  
  19.     curl_setopt($ch, CURLOPT_ENCODING, "");    // 设置编码  
  20.     curl_setopt($ch, CURLOPT_REFERER, $url);   // 伪造来源网址  
  21.     curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:'.$ip, 'CLIENT-IP:'.$ip));  //伪造IP  
  22.     curl_setopt($ch, CURLOPT_USERAGENT, $ua);   // 伪造ua   
  23.     curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // 取消gzip压缩  
  24.     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts  
  25.     curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);  
  26.     $content = curl_exec($ch);   
  27.     curl_close($ch);    // 结束 Curl  
  28.     return $content;    // 函数返回内容  
  29. }  
  30.   
  31. ?>  

通过修改 IP 值,你就可以获取任意 IP 对应的地址了 [坏笑] 一个 IP 查询工具就这样诞生了!

然鹅,,你肯定也注意到了。以上获取到的数据内容似乎有点乱:
从零开始,学会 PHP 采集

如果我只想获取到其中的省份和城市信息,该怎么办呢?

细心的你肯定发现了,这个数据并不是 JSON 格式的,因此也就不能通过上文的 解析 JSON 的方法来进行解析。那该怎么办呢?

正则表达式入门

每到要从一堆杂乱的内容中获取内容,就是正则表达式登场的时候了!

仔细观察返回的数据,其实内容中除了城市和省份,其它的内容是固定的,格式如下:

var lo="省份", lc="城市";

我们可以以此来编写正则表达式。推荐使用 站长工具的正则表达式测试工具(http://tool.chinaz.com/regex/),可以实时测试匹配结果,很方便。没接触过正则表达式的也可以查阅工具中的正则表达式语法说明来现学。

这是我写好的正则表达式内容。可以完美地匹配出需要的内容

  1. lo="(.*)", lc="(.*)";  

从零开始,学会 PHP 采集

有了正则表达式,再就需要用 PHP 来从原始数据中来匹配出来了。于是乎我们又用上了一个新的 PHP 函数:preg_match()

它的用法是这样的:

  1. preg_match('正则表达式', '输入内容', '存储匹配结果的变量’)  

又到了上代码的时间:

  1. <?php  
  2. $data = myCurl('http://ip.ws.126.net/ipquery', '223.81.141.38');    // 伪造 IP 并获取数据  
  3.   
  4. preg_match('/lo="(.*)", lc="(.*)";/', $data$arr);    // 正则提取  
  5.   
  6. /** 
  7. 注: 
  8. 正则表达式中括号括起来的部分代表要匹配的内容, 
  9. 像上面这个正则表达式中有两个括号括起来的部分,自然就代表会匹配出两个内容。 
  10.  
  11. 正则匹配的结果会以【数组】的形式赋值给第三个参数,也就是 $arr 
  12.  
  13. 那么……  
  14. $arr[0]是整个正则表达式匹配出的内容(无视括号) 
  15. $arr[1]是第一个括号中匹配出的内容 
  16. $arr[2]是第二个括号中匹配出的内容 
  17. . 
  18. . 
  19. $arr[n]是第N个括号中匹配出的内容(如果有的话。。) 
  20. **/   
  21.   
  22. echo $arr[1].' - '.$arr[2];    // 输出  
  23.   
  24.   
  25.   
  26. /** 
  27.  * Curl 伪造 IP 并从指定网址获取数据 
  28.  * @param $url 接口地址 
  29.  * @param $ip 伪造的 IP 
  30.  * @return 抓取到的内容 
  31.  */  
  32. function myCurl($url$ip){   
  33.     $ch = curl_init();     // Curl 初始化  
  34.     $timeout = 30;     // 超时时间:30s  
  35.     $ua='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36';    // 伪造抓取 UA  
  36.     curl_setopt($ch, CURLOPT_URL, $url);              // 设置 Curl 目标  
  37.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);      // Curl 请求有返回的值  
  38.     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);     // 设置抓取超时时间  
  39.     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);        // 跟踪重定向  
  40.     curl_setopt($ch, CURLOPT_ENCODING, "");    // 设置编码  
  41.     curl_setopt($ch, CURLOPT_REFERER, $url);   // 伪造来源网址  
  42.     curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:'.$ip, 'CLIENT-IP:'.$ip));  //伪造IP  
  43.     curl_setopt($ch, CURLOPT_USERAGENT, $ua);   // 伪造ua   
  44.     curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // 取消gzip压缩  
  45.     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts  
  46.     curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);  
  47.     $content = curl_exec($ch);   
  48.     curl_close($ch);    // 结束 Curl  
  49.     return $content;    // 函数返回内容  
  50. }  
  51.   
  52. ?>  

结束语

本文从零开始,大致地讲了下使用 PHP 抓取数据并进行解析、获取自己想要的内容的方法,旨在起到一个抛砖引玉的作用。因为时间及水平有限,可能有些地方说得比较笼统。

如果还要不懂的地方,可以尝试通过百度来解惑,百度上的很多教程都比较详细。

如果有百度了还没解决的问题,可以直接在下面留言。

发表评论 取消回复
表情 图片 链接 代码

  1. 互联影吧
    互联影吧 Lv 1

    电影网采集API,自动更新,会做吗?回复我一下

  2. 琪琳
    琪琳 Lv 1

    只会python的爬虫,想不到PHP也可以

  3. 小灵
    小灵 Lv 3

    那么问题来了
    查看图片
    这种情况怎么弄呢
    查看图片
    还有这种,为什么这种接口可以用html的代码来实现

  4. 菜鸟
    菜鸟 Lv 1

    自学半个月,就需要这样干货,多多更新[aru_89]

  5. 菜鸡
    菜鸡 Lv 1

    网上很少有php采集的教程,希望博主能高产似母猪[aru_3]

  6. Song
    Song Lv 1

    如果要爬取好几层呢,
    curl_setopt($ch, CURLOPT_URL, $url); // 设置 Curl 目标
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Curl 请求有返回的值
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置抓取超时时间
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 跟踪重定向
    curl_setopt($ch, CURLOPT_ENCODING, ""); // 设置编码
    curl_setopt($ch, CURLOPT_REFERER, $url); // 伪造来源网址
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:'.$ip, 'CLIENT-IP:'.$ip)); //伪造IP
    curl_setopt($ch, CURLOPT_USERAGENT, $ua); // 伪造ua
    curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // 取消gzip压缩
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    这一段要写好几遍吗?

    • mengkun
      mengkun 站长

      @Song不是封装好了函数吗,直接多调用几次 myCurl($url, $ip) 就行了。
      例如:

      $baidu =  myCurl('https://www.baidu.com', '');
      $google =  myCurl('https://www.google.com', '');
      ……
  7. Roogle
    Roogle Lv 1

    嗯,继续出教程,不要停

  8. 太小白
    太小白 Lv 1

    表示本菜鸟看不懂

  9. 献上我的膝盖
    献上我的膝盖 Lv 1

    请教一下站长,我使用你这个文章的curl拿到了百度音乐的播放地址,但是在http打开页面的发起请求拿到的地址,添加到audio标签,却不能播放,返回403报错,提示被禁止访问,没有权限。这个能解决吗?[aru_15]

  10. 365cent
    365cent Lv 3

    能抓一言的吗?我想自己搭个同步的api

  11. 乐儿
    乐儿 Lv 1

    大佬,我把你的评论扒走用行不?[aru_18]

  12. hackzt
    hackzt Lv 1

    很不错,希望长更新

  13. 蓝叶
    蓝叶 Lv 1

    这教程写的不错,适合新手学习,更是适合懒人直接复制粘贴就能用了。

    • mengkun
      mengkun 站长

      @蓝叶活捉蓝叶大佬 [wb_doge]

  14. woorz
    woorz Lv 1

    非常好,适合我等菜鸟,茅塞顿开啊

  15. 小李
    小李 Lv 1

    php抓取没什么问题,之前做过微信模拟之类的,但 是记得IP不是这么轻易可以伪造的吧,,好像终极方法是IP代理,这有点不好弄,我没有试试过

    • mengkun
      mengkun 站长

      @小李PHP 只能伪造 HTTP_CLIENT_IP 和 HTTP_X_FORWARDED_FOR。通过伪造这两项已经能“骗”过大多数的程序了。
      如果对方是通过 REMOTE_ADDR 来进行判断,那么只能是用代理了。但使用代理也只能是变成成代理服务器的 IP 地址,并不能达成想随意伪造 IP 的目的。

  16. 天空树
    天空树 Lv 1

    不错

  17. 死神影视
    死神影视 Lv 2

    博主,我问个问题,我的影视网站获取的360列表,但是我添加了尝鲜电影,如图 查看图片
    我是直接新建了一个li.php页面添加的电影列表,然后在index里添加了include 'li.php',显示正常,列表代码截图如下:
    查看图片
    但是我添加电影需要去编辑代码比较麻烦。现在想通过比如新建一个页面,在这个页面有几个表单框,填写播放链接、图片地址等信息之后前段自动显示,这样的是不是很麻烦?如果不麻烦的话请指点一下,如果麻烦的话我就放弃了。。。

    • mengkun
      mengkun 站长

      @死神影视你的意思就是做一个后台是吧?
      其实只是少量的数据修改弄后台没必要,确实有些复杂。
      你可以把这些可复用的内容(<li>中间的内容)写成一个函数,然后通过函数来调用输出。比如
      function movie($name, $url, $cover) {
      .......
      }
      然后通过
      movie('电影名','链接','封面');
      这种形式来输出,就简单些。

      • 死神影视
        死神影视 Lv 2

        @mengkun好吧,复杂的话我就不弄了,没学过这个,复杂的我弄不来。。只会修改一点代码,关于程序是一点不懂。。。谢谢了。

  18. 游魂
    游魂 Lv 1

    博主 用jsonp的方式能不能做到呢?

    • mengkun
      mengkun 站长

      @游魂有的接口支持 jsonp,有的不支持。本文主题是使用 PHP 抓取解析,所以特意都选的不支持 jsonp 的接口作为示例

      • 游魂
        游魂 Lv 1

        @mengkun哦哦 有个问题求助下 我用的emlog的邮件smtp插件 死活不能用 有时间能帮我看看原因么?

      • mengkun
        mengkun 站长

        @游魂不能。没时间。对 emlog 不了解。不过猜测是服务器发送邮件的端口被封堵引起的,因为最近一大批服务器都封堵了通常用于发送邮件的 25 端口。办法是换一个不用 25 端口的邮件发送方式(具体请百度)

      • summer
        summer Lv 1

        @游魂坤哥说的不错,端口封堵,解决办法,用qq邮箱,改一下代码,smtp为qq,端口465,完美解决。

  19. djmingge
    djmingge Lv 2

    获取360数据,很多需要正则表达式

  20. djmingge
    djmingge Lv 2

    mk大佬真流弊。虽然看了也还是不怎么懂,可以慢慢看

  21. 零度
    零度 Lv 1

    牛逼 这姿势可以 我居然能看完这么长的文章。看起来挺简单的

  22. jwong
    jwong Lv 2

    实在太棒了,我经常会来看看有没有新的东西,知识也好,生活趣事也好,都乐意看一看,最近我决心要学织梦仿站,从代码开始学起!

  23. fy789
    fy789 Lv 1

    不懂英文,学起来好像很费劲!!!!!!!!!

    • mengkun
      mengkun 站长

      @fy789编程与英文水平的高低没有必然的联系。
      你可以将里面的字母当做拼音来看,是一样的。
      因为就算是认识这些单词的外国人学起来还是得一个个去学习它的具体的用法

  24. h
    h Lv 1

    打卡打卡! [wb_二哈]

  25. 现实君
    现实君 Lv 3

    打卡..嘀嘀嘀...

  26. 阿珏博客
    阿珏博客 Lv 1

    看样子这是一个系列的文章 [疑问] 多发些,我也学习学习

  27. 玖月
    玖月 Lv 1

    感谢分享

  28. 广元巴士
    广元巴士 Lv 5

    如此长文,叫我如何消化。只有两个字适合我——远离

    • mengkun
      mengkun 站长

      @广元巴士一步步来尝试,你会发现其实很简单。
      等到学会了会有一种"相识恨晚"的感觉 #(滑稽)
      因为这项技能的用处实在是太多了 #(笑眼)

  29. 游魂
    游魂 Lv 1

    不错 特别详细

  30. 陌小雨
    陌小雨 Lv 1

    很棒的教程,内容很丰富,涉及到php语法、json数据解析、php正则、php函数,感谢分享

分享