从零开始,学会 PHP 采集

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

通过修改 IP 值,你就可以获取任意 IP 对应的地址了

一个 IP 查询工具就这样诞生了!

然鹅,,你肯定也注意到了。以上获取到的数据内容似乎有点乱:

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

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

正则表达式入门

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

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

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

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

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

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

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

它的用法是这样的:

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

又到了上代码的时间:

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

结束语

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏章鱼的慢慢技术路

《算法图解》第五章笔记与课后练习_散列函数与散列表

1735
来自专栏积累沉淀

Javascript模块化编程(一)

随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂。 网页越来越像桌面程序,需要一个团队分工协作、进度管理、单元测...

35410
来自专栏程序员宝库

JAVA 中异常处理的最佳实践

前言 异常处理的问题之一是知道何时以及如何去使用它。我会讨论一些异常处理的最佳实践,也会总结最近在异常处理上的一些争论。 作为程序员,我们想要写高质量的能够解决...

2968
来自专栏逢魔安全实验室

CVE-2018-2628 Weblogic反序列化POC重构详解

3475
来自专栏Java架构师学习

编写 Spring 配置文件的最佳实践

Spring 是一个功能强大的Java应用框架,提供各种配置选项。它的核心特性是为简单的Java对象(PO??JO)提供服务,称为 Bean。 Spring使用...

3357
来自专栏python3

python3--文件操作

rb,只读,以bytes类型读取(非文字类的文件时,用rb,比如图片,音频文件等)

932
来自专栏欧阳大哥的轮子

iOS的MVC框架之控制层的构建(上)

在我前面的两篇文章里面分别对MVC框架中的M层的定义和构建方法进行了深入的介绍和探讨。这篇文章则是想深入的介绍一下我们应该如何去构建控制层。控制层是联系视图层和...

922
来自专栏FreeBuf

挖洞经验 | 如何在一条UPDATE查询中实现SQL注入

前段时间,我在对Synack漏洞平台上的一个待测试目标进行测试的过程中发现了一个非常有意思的SQL注入漏洞,所以我打算在这篇文章中好好给大家介绍一下这个有趣的漏...

2155
来自专栏瓜大三哥

​UVM(九)之sequencej机制续1

UVM(九)之sequencej机制续1 当一个sequence启动起来之后,UVM会自动执行sequence的body任务,所以要产生各种和杨的激励,就要写好...

22410
来自专栏Java帮帮-微信公众号-技术文章全总结

Java并发编程,一定要有自己的理解【面试+工作】

编写优质的并发代码是一件难度极高的事情。Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的,但是当我们对并发编程有了更深刻的认识和更多的...

1187

扫码关注云+社区