1.PHP简单的爬虫–原型

爬虫的原理:

  • 给定原始的url;
  • 分析链接,根据设置的正则表达式获取链接中的内容;
  • 有的会更新原始的url再进行分析链接,获取特定内容,周而复始。
  • 将获取的内容保存在数据库中(mysql)或者本地文件中

下面是网上一个例子,我们列下来然后分析 
main函数开始

<?php
/**
* 爬虫程序 -- 原型
*
* 从给定的url获取html内容
*
* @param string $url
* @return string
*/
function _getUrlContent($url) {
$handle = fopen($url, "r");
if ($handle) {
$content = stream_get_contents($handle, -1);
//读取资源流到一个字符串,第二个参数需要读取的最大的字节数。默认是-1(读取全部的缓冲数据)
// $content = file_get_contents($url, 1024 * 1024);
return $content;
} else {
return false;
}
}
/**
* 从html内容中筛选链接
*
* @param string $web_content
* @return array
*/
function _filterUrl($web_content) {
$reg_tag_a = '/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\ ]*).*?>/';
$result = preg_match_all($reg_tag_a, $web_content, $match_result);
if ($result) {
return $match_result[1];
}
}
/**
* 修正相对路径
*
* @param string $base_url
* @param array $url_list
* @return array
*/
function _reviseUrl($base_url, $url_list) {
$url_info = parse_url($base_url);//解析url
$base_url = $url_info["scheme"] . '://';
if ($url_info["user"] && $url_info["pass"]) {
$base_url .= $url_info["user"] . ":" . $url_info["pass"] . "@";
}
$base_url .= $url_info["host"];
if ($url_info["port"]) {
$base_url .= ":" . $url_info["port"];
}
$base_url .= $url_info["path"];
print_r($base_url);
if (is_array($url_list)) {
foreach ($url_list as $url_item) {
if (preg_match('/^http/', $url_item)) {
// 已经是完整的url
$result[] = $url_item;
} else {
// 不完整的url
$real_url = $base_url . '/' . $url_item;
$result[] = $real_url;
}
}
return $result;
} else {
return;
}
}
/**
* 爬虫
*
* @param string $url
* @return array
*/
function crawler($url) {
$content = _getUrlContent($url);
if ($content) {
$url_list = _reviseUrl($url, _filterUrl($content));
if ($url_list) {
return $url_list;
} else {
return ;
}
} else {
return ;
}
}
/**
* 测试用主程序
*/
function main() {
$file_path = "url-01.txt";
$current_url = "http://www.baidu.com/"; //初始url
if(file_exists($file_path)){
unlink($file_path);
}
$fp_puts = fopen($file_path, "ab"); //记录url列表
$fp_gets = fopen($file_path, "r"); //保存url列表
do {
$result_url_arr = crawler($current_url);
if ($result_url_arr) {
foreach ($result_url_arr as $url) {
fputs($fp_puts, $url . "\r\n");
}
}
} while ($current_url = fgets($fp_gets, 1024)); //不断获得url
}
main();
?>

2.使用crul lib

Curl是比较成熟的一个lib,异常处理、http header、POST之类都做得很好,重要的是PHP下操作MySQL进行入库操作比较省心。关于curl的说明具体可以查看PHP官方文档说明http://php.net/manual/zh/book.curl.php 
不过在多线程Curl(Curl_multi)方面比较麻烦。

开启crul 
针对winow系统: 
- php.in中修改(注释;去掉即可)

extension=php_curl.dll

  • php文件夹下的libeay32.dll, ssleay32.dll, libssh2.dll 还有 php/ext下的php_curl4个文件移入windows/system32

使用crul爬虫的步骤: 
- 使用cURL函数的基本思想是先使用curl_init()初始化一个cURL会话; 
- 接着你可以通过curl_setopt()设置你需要的全部选项; 
- 然后使用curl_exec()来执行会话; 
- 当执行完会话后使用curl_close()关闭会话。

例子

<?php
$ch = curl_init("http://www.example.com/");
$fp = fopen("example_homepage.txt", "w"); curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec($ch);
curl_close($ch);
fclose($fp);
?>

一个完整点的例子:

<?php
/**
* 将demo1-01换成curl爬虫
* 爬虫程序 -- 原型
* 从给定的url获取html内容
* @param string $url
* @return string
*/
function _getUrlContent($url) {
$ch=curl_init(); //初始化一个cURL会话
/*curl_setopt 设置一个cURL传输选项*/
//设置需要获取的 URL 地址
curl_setopt($ch,CURLOPT_URL,$url);
//TRUE 将curl_exec()获取的信息以字符串返回,而不是直接输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//启用时会将头文件的信息作为数据流输出
curl_setopt($ch,CURLOPT_HEADER,1);
// 设置浏览器的特定header
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Host: www.baidu.com",
"Connection: keep-alive",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Upgrade-Insecure-Requests: 1",
"DNT:1",
"Accept-Language: zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4,en-US;q=0.2",
/*'Cookie:_za=4540d427-eee1-435a-a533-66ecd8676d7d; */
));
$result=curl_exec($ch);//执行一个cURL会话
$code=curl_getinfo($ch,CURLINFO_HTTP_CODE);// 最后一个收到的HTTP代码
if($code!='404' && $result){
return $result;
}
curl_close($ch);//关闭cURL
}
/**
* 从html内容中筛选链接
* @param string $web_content
* @return array
*/
function _filterUrl($web_content) {
$reg_tag_a = '/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\ ]*).*?>/';
$result = preg_match_all($reg_tag_a, $web_content, $match_result);
if ($result) {
return $match_result[1];
}
}
/**
* 修正相对路径
* @param string $base_url
* @param array $url_list
* @return array
*/
function _reviseUrl($base_url, $url_list) {
$url_info = parse_url($base_url);//解析url
$base_url = $url_info["scheme"] . '://';
if ($url_info["user"] && $url_info["pass"]) {
$base_url .= $url_info["user"] . ":" . $url_info["pass"] . "@";
}
$base_url .= $url_info["host"];
if ($url_info["port"]) {
$base_url .= ":" . $url_info["port"];
}
$base_url .= $url_info["path"];
print_r($base_url);
if (is_array($url_list)) {
foreach ($url_list as $url_item) {
if (preg_match('/^http/', $url_item)) {
// 已经是完整的url
$result[] = $url_item;
} else {
// 不完整的url
$real_url = $base_url . '/' . $url_item;
$result[] = $real_url;
}
}
return $result;
} else {
return;
}
}
/**
* 爬虫
* @param string $url
* @return array
*/
function crawler($url) {
$content = _getUrlContent($url);
if ($content) {
$url_list = _reviseUrl($url, _filterUrl($content));
if ($url_list) {
return $url_list;
} else {
return ;
}
} else {
return ;
}
}
/**
* 测试用主程序
*/
function main() {
$file_path = "./url-03.txt";
if(file_exists($file_path)){
unlink($file_path);
}
$current_url = "http://www.baidu.com"; //初始url
//记录url列表  ab- 追加打开一个二进制文件,并在文件末尾写数据
$fp_puts = fopen($file_path, "ab");
//保存url列表 r-只读方式打开,将文件指针指向文件头
$fp_gets = fopen($file_path, "r");
do {
$result_url_arr = crawler($current_url);
echo "<p>$current_url</p>";
if ($result_url_arr) {
foreach ($result_url_arr as $url) {
fputs($fp_puts, $url . "\r\n");
}
}
} while ($current_url = fgets($fp_gets, 1024)); //不断获得url
}
main();
?>

要对https支持,需要在_getUrlContent函数中加入下面的设置:

curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ;
curl_setopt($ch, CURLOPT_USERPWD, "username:password");
curl_setopt($ch, CURLOPT_SSLVERSION,3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

结果疑惑: 
我们通过1和2部分得到的结果差异很大,第1部分能得到四千多条url数据,而第2部分却一直是45条数据。

还有我们获得url数据可能会有重复的,这部分处理在我的github上,对应demo2-01.php,或者demo2-02.php

3.file_get_contents/stream_get_contents与curl对比

3.1 file_get_contents/stream_get_contents对比

  stream_get_contents — 读取资源流到一个字符串 
  与 [file_get_contents()]一样,但是 stream_get_contents() 是对一个已经打开的资源流进行操作,并将其内容写入字    符串返回

$handle = fopen($url, "r");
$content = stream_get_contents($handle, -1);//读取资源流到一个字符串,第二个参数需要读取的最大的字节数。默认是-1(读取全部的缓冲数据)

file_get_contents — 将整个文件读入一个字符串

$content = file_get_contents($url, 1024 * 1024);

【注】 如果要打开有特殊字符的 URL (比如说有空格),就需要使用进行 URL 编码。

3.2 file_get_contents/stream_get_contents与curl对比

php中file_get_contents与curl性能比较分析一文中有详细的对比分析,主要的对比现在列下来: 
- fopen /file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。

  • fopen /file_get_contents 在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。

  • fopen / file_get_contents 函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。

  • curl 可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。

4.使用框架

使用框架这一块打算以后单独研究,并拿出来单写一篇博客

所有代码挂在我的github上。

 

个人公众号谢谢各位老铁支持

 
 
 

PHP简单的爬虫–原型的更多相关文章

  1. PHP实现最简单爬虫原型

    本人qq群也有许多的技术文档,希望可以为你提供一些帮助(非技术的勿加). QQ群:   281442983 (点击链接加入群:http://jq.qq.com/?_wv=1027&k=29Lo ...

  2. Selenium + PhantomJS + python 简单实现爬虫的功能

    Selenium 一.简介 selenium是一个用于Web应用自动化程序测试的工具,测试直接运行在浏览器中,就像真正的用户在操作一样 selenium2支持通过驱动真实浏览器(FirfoxDrive ...

  3. asp.net简单小爬虫

    所谓爬虫简单点说,就是把别人网站上的东西爬下来,至于爬做什么用就看你自己了,比如:把别人网站上的东西爬下来放在自己网站中(感觉有点像小偷^v^). 这里随便写了一个爬虫代码(可以自己再去进行完善): ...

  4. python (1)一个简单的爬虫: python 在windows下 创建文件夹并写入文件

    1.一个简单的爬虫:爬取豆瓣的热门电影的信息 写在前面:如何创建本来存在的文件夹并写入 t_path = "d:/py/inn" #本来不存在inn,先定义路径,然后如果不存在,则 ...

  5. 一个简单java爬虫爬取网页中邮箱并保存

    此代码为一十分简单网络爬虫,仅供娱乐之用. java代码如下: package tool; import java.io.BufferedReader; import java.io.File; im ...

  6. 用python3.x与mysql数据库构建简单的爬虫系统(转)

    这是在博客园的第一篇文章,由于本人还是一个编程菜鸟,也写不出那些高大上的牛逼文章,这篇文章就是对自己这段时间学习python的一个总结吧. 众所周知python是一门对初学编程的人相当友好的编程语言, ...

  7. 纯手工打造简单分布式爬虫(Python)

    前言 这次分享的文章是我<Python爬虫开发与项目实战>基础篇 第七章的内容,关于如何手工打造简单分布式爬虫 (如果大家对这本书感兴趣的话,可以看一下 试读样章),下面是文章的具体内容. ...

  8. nodejs实现最简单的爬虫

    本文将以抓取百度搜索结果中关键词的相关搜索为例子,教会大家以nodejs制作最简单的爬虫:  开始之前呢,先来个公众号求粉:      将使用的node模块及属性介绍:   request:     ...

  9. 视频博文结合的教程:用nodejs实现简单的爬虫

    教学视频地址: https://v.qq.com/x/page/b0643tut4ze.html 前言   本喵最近工作中需要使用node,并也想晋升为全栈工程师,所以开始了node学习之旅,在学习过 ...

随机推荐

  1. win 10 hosts文件不生效

    win 10 hosts文件不生效       windows 10 hosts文件修改了,但是怎么都无法在浏览器中进行解析.一直都在等待,直到链接超时. 最后解决办法: 把hosts文件内容复制出来 ...

  2. maven之阿里云Maven镜像的使用

    Maven中央仓库在国外,速度比较慢,所以我们采用国内的镜像,速度回有质的提升. 配置下setting.xml <mirrors> <mirror> <id>ali ...

  3. leetcode206 反转链表 两种做法(循环,递归)

    反转链表 leetcode206 方法1 循环 public ListNode reverseList(ListNode head) { if (head == null || head.next = ...

  4. CentOS7 nginx安装与卸载

    简明清晰,易操作,参照: CentOS7 nginx安装与卸载

  5. IDEA反编译jar包源码

    1.maven 项目查看jar源码 如何在idea中查看jar包源码   文章目录 准备jar包 idea打开文件夹 最后一步 准备jar包 例如,我准备看resin的jar,在桌面准备了一份 ide ...

  6. 正则表达式分组(Grouping)

    一 捕获型 (x) 匹配 x ,并且捕获匹配项 const regExp = /(\w+)\s+(\d+)/; const str = 'Android 8'; str.replace(regExp, ...

  7. mysql5.6修改密码并授权所有远程用户可登陆

    1.my.ini文件,删除最后一行的"skip-grant-tables 2.执行"use mysql;",使用mysql数据库; 3.执行:update mysql.u ...

  8. 第六周总结&第四次实验报告

    实验四 类的继承 一. 实验目的 (1) 掌握类的继承方法: (2) 变量的继承和覆盖,方法的继承.重载和覆盖实现: 二. 实验内容 三.实验过程 实验代码 package Shiyan4; publ ...

  9. springboot + mybaits + oracle 项目

    1.pom设置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  10. Docker最详细入门教程

    Docker原理.详细入门教程 https://blog.csdn.net/deng624796905/article/details/86493330 阮一峰Docker入门讲解 http://ww ...