PHP 实现网页爬虫

2023-11-04

方法一

通过fopen和stream_get_contents获取html内容

从给定的url获取html内容

/**
     * 爬虫程序 -- 原型
     * 从给定的url获取html内容
     * 通过fopen和stream_get_contents获取html内容
     * @param string $url 
     * @return string 
     */
    function _getUrlContent($url)
    {
        //fopen() 函数打开一个文件或 URL。
        $handle = fopen($url, "r");
        // var_dump($handle);die;

        if ($handle) {
            //官方是这样描述的与 stream_get_contents();file_get_contents() 一样,但是 stream_get_contents() 是对一个已经打开的资源流进行操作,并将其内容写入一个字符串返回
            $content = stream_get_contents($handle, 1024 * 1024);
            return $content;
        } else {
            return false;
        }
    }

从html内容中筛选链接。爬取信息,可直接调用

/**
     * 从html内容中筛选链接。爬取信息,可直接调用
     * @param string $web_content
     * @param  [type] $tag   [要查找的标签]
     * @param  [type] $attr  [要查找的属性名]
     * @param  [type] $value [属性名对应的值]
     * @return array 
     */
    function _filterUrl($web_content)
    {
        $tag = 'div';
        $attr = '';
        $value = '';
        //自定义正则表达式
        $reg_tag_a = "/<$tag.*?$attr=\".*?$value.*?\".*?>(.*?)<\/$tag>/is";
        //获取页面所有链接的正则表达式
        //$reg_tag_a = "/<[a|A].*?href=[\'\"]{0,1}([^>\'\"\ ]*).*?>/";
        
		//preg_match_all 函数用于执行一个全局正则表达式匹配。
		//参数一:$pattern: 要搜索的模式,字符串形式。
		//参数二:$subject: 输入字符串。
		//参数三:$matches: 多维数组,作为输出参数输出所有匹配结果, 数组排序通过flags指定。
		//参数四:$flags:匹配模式,默认PREG_PATTERN_ORDER
        $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);
        // var_dump($url_info);die;
        $base_url = $url_info["scheme"] . '://';
        if (isset($url_info["user"]) && isset($url_info["pass"])) {
            $base_url .= $url_info["user"] . ":" . $url_info["pass"] . "@";
        }
        $base_url .= $url_info["host"];
        if (isset($url_info["port"])) {
            $base_url .= ":" . $url_info["port"];
        }
        $base_url .= $url_info["path"];
        // print_r($url_list);
        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;
        }
    }

修正链接,可不调用,直接调用_filterUrl

/**
     * 爬虫 其实就是修正链接,可不调用,直接调用_filterUrl
     * @param string $url 
     * @return array 
     */
    function crawler($url)
    {
        // $url = g('url') ?? '';
        $content = $this->_getUrlContent($url);
        // var_dump($content);die;
        if ($content) {
            $url_list = $this->_reviseUrl($url, $this->_filterUrl($content));
            // var_dump($url_list);die;
            if ($url_list) {
                return $url_list;
            } else {
                return;
            }
        } else {
            return;
        }
    }

测试用主程序,往文件里写入爬虫信息

/**
     * 测试用主程序,往文件里写入爬虫信息
     */
    public function main()
    {
        $current_url = "https://www.sina.com.cn/"; //初始url
        $fp_puts = fopen("url3.txt", "ab"); //记录url列表
        $fp_gets = fopen("url3.txt", "r"); //保存url列表
        do {
            $result_url_arr = $this->crawler($current_url);
            // var_dump($result_url_arr);die;
            if ($result_url_arr) {
                foreach ($result_url_arr as $url) {
                    fputs($fp_puts, $url . "\r\n");
                }
            }
        } while ($current_url = fgets($fp_gets, 1024)); //不断获得url
    }

方法二

使用curl获取html页面内容

使用curl获取html页面内容

/**
     * [curlHtml 获取页面信息]
     * 使用curl获取html页面内容
     * @param  [type] $url [网址]
     * @return [type]      [description]
     */

    function curlHtml($url)
    {
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL            => "{$url}",
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING       => "",
            CURLOPT_MAXREDIRS      => 10,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST  => "GET",
            CURLOPT_HTTPHEADER     => array(
                "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                "Accept-Encoding: gzip, deflate, br",
                "Accept-Language: zh-CN,zh;q=0.9",
                "Cache-Control: no-cache",
                "Connection: keep-alive",
                "Pragma: no-cache",
                "Upgrade-Insecure-Requests: 1",
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
                "cache-control: no-cache"
            ),
        ));

        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        $response = curl_exec($curl);
        $err = curl_error($curl);
        curl_close($curl);
        if ($err) return false;
        else return $response;
    }

使用正则获取html内容中指定的内容

/**
     * [get_tag_data 使用正则获取html内容中指定的内容]
     * @param  [type] $html  [爬取的页面内容]
     * @param  [type] $tag   [要查找的标签]
     * @param  [type] $attr  [要查找的属性名]
     * @param  [type] $value [属性名对应的值]
     * @return [type]        [description]
     */
    function get_tag_data($html, $tag, $attr, $value)
    {

        // var_dump($tag, $attr, $value);
        $regex = "/<$tag.*?$attr=\".*?$value.*?\".*?>(.*?)<\/$tag>/is";
        // var_dump($regex);
        preg_match_all($regex, $html, $matches, PREG_PATTERN_ORDER);
        var_dump($matches);die;
        $data = isset($matches[1]) ? $matches[1] : '';
        // var_dump($data);die;
        return $data;
    }

使用xpath对获取到的html内容进行处理

/**
     * [get_html_data 使用xpath对获取到的html内容进行处理]
     * @param  [type]  $html [爬取的页面内容]
     * @param  [type]  $path [Xpath语句]
     * @param  integer $tag  [类型 0内容 1标签内容 自定义标签]
     * @param  boolean $type [单个 还是多个(默认单个时输出单个)]
     * @return [type]        [description]
     */

    function get_html_data($html, $path, $tag = 1, $type = true)
    {
        $dom = new \DOMDocument();
        @$dom->loadHTML("<?xml encoding='UTF-8'>" . $html); // 从一个字符串加载HTML并设置UTF8编码
        $dom->normalize(); // 使该HTML规范化
        $xpath = new \DOMXPath($dom); //用DOMXpath加载DOM,用于查询
        $contents = $xpath->query($path); // 获取所有内容
        $data = [];
        foreach ($contents as $value) {
            if ($tag == 1) {
                $data[] = $value->nodeValue; // 获取不带标签内容
            } elseif ($tag == 2) {
                $data[] = $dom->saveHtml($value);  // 获取带标签内容
            } else {
                $data[] = $value->attributes->getNamedItem($tag)->nodeValue; // 获取attr内容
            }
        }
        if (count($data) == 1) {
            $data = $data[0];
        }
        return $data;
    }

测试程序,调用

//调用
    public function get_content()
    {
        $url = g('url') ?? '';
        $tag = g('tag') ?? '';
        $attr = g('attr') ?? '';
        $value = g('value') ?? '';
        if (empty($url) || empty($tag)) {
            resultInfo(4, '缺少关键参数!');
        }

        $html = $this->curlHtml($url);
        //使用正则获取
        $data = $this->get_tag_data($html, $tag, $attr, $value);
        //Xpath方法,暂未搞明白
        // $data = $this->get_html_data($html, $path, $tag = 1, $type = true);
        resultInfo(1, 'ok!', $data);
    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PHP 实现网页爬虫 的相关文章

  • 我如何知道是否启用了 PHP 缓存?

    我曾经认为缓存很难安装 所以我从来没有这样做过 在阅读了有关 APC 的内容后 它似乎很容易安装 我一直认为我必须修改应用程序中的大量 PHP 代码才能使用它 哈哈 不管怎样 我想安装APC 我可以使用 phpinfo 并注意到它没有在页面
  • 子目录中的 CakePHP 控制器和模型

    你好 我想知道如何将我的组件和模型放在子目录中 假设我有一个 Web 应用程序 它有 3 个不同的区域 管理员 用户 开发人员 每个区域执行不同的操作并具有完全不同的界面 所以我希望管理员去http www site com admin h
  • WooCommerce:在未登录用户的结帐页面中默认设置国家/地区

    如何将国家 地区设为常规 未注册用户 的默认国家 地区 但如果买家有个人账户并进入该国 他在结帐时不会被拖欠吗 我尝试过使用WooCommerce 在结帐页面中默认设置国家 地区 https stackoverflow com questi
  • preg_match_all JS 等效吗?

    Javascript 中是否有与 PHP 的 preg match all 等效的函数 如果没有 将正则表达式的所有匹配项放入数组的最佳方法是什么 我愿意使用任何 JS 库来让它变得更容易 您可以使用match使用全局修饰符 gt gt g
  • PHP 生成文件供下载然后重定向

    我有一个 PHP 应用程序 它创建一个 CSV 文件 强制使用标头下载该文件 这是代码的相关部分 header Content Type application csv header Content length filesize NewF
  • 如何在xampp中启用zip.dll

    你好 我正在使用 Windows 版 xampp 我想运行 https github com johmue mysql workbench schema exporter 导出我的架构 我在 mysql 工作台中创建架构并保存它 当我运行程
  • PHP exec rm -Rf 不适用于子目录

    我试图删除特定文件夹中的所有内容 但它似乎不会影响子文件夹 但它应该 因为 bash 命令是从控制台执行的 system rm Rf some dir 该命令中不需要星号 如果要与文件一起删除目录 请同时删除斜杠 留下斜杠将删除文件 但保留
  • Doctrine 不会在 MySQL 中生成跨数据库外键约束

    我有两个表 db1 Contact 和 db2 Recipient 每个收件人都应该是联系人 因此我在 db1 Contact ContactID 字段上的两个表之间设置了外键 我在 Recipient php 中使用以下注释表示这一点 O
  • 使用 chr + rand 生成随机字符 (A-Z)

    我使用以下命令生成 A Z 的随机字符 但它偶尔会生成 符号 知道如何防止这种情况吗 也许字符范围不正确 letter chr 64 rand 0 26 用这个就更方便了 大写 letter chr rand 65 90 小写 letter
  • 防止重复数据输入mysql数据库

    我试图让我的电子邮件订阅服务拒绝数据库中已存在的电子邮件 这样用户就不会订阅同一封电子邮件两次 这就是我所拥有的 但它不起作用 有什么想法吗
  • 如何在 php 中访问名为变量的对象属性?

    以 JSON 编码的 Google API 返回一个如下所示的对象 updated gt stdClass Object t gt 2010 08 18T19 17 42 026Z 任何人都知道我如何访问 t value object gt
  • drupal 7 将实际内容存储在数据库中的哪里?

    我打开了 drupal 7 的数据库并在表中查找node node revisions and node types并且找不到 drupal 存储实际的位置body节点 内容 的 有人有线索吗 哦 我刚刚找到了 在 D7 中 他们实现了字段
  • WooCommerce:检查商品是否已在购物车中

    我从中发现了这个很棒的片段website https joebuckle me quickie woocommerce check if item already in cart 以下是检查购物车中是否存在特定产品的函数 function
  • PHP-向某些浏览器显示消息

    我已经搜索过这个 我发现的一切都超出了我的需要 我以前用 JavaScript 做过这个 但我真的更喜欢使用 PHP 我将如何根据访问者使用的浏览器向他们显示消息 Example IE 用户会看到 您正在使用 Internet Explor
  • 如何使用 PHP 通过 JSON 发送 HTML 元素?

    以下功能 try query this gt pdo gt prepare SELECT FROM bookings WHERE TourID AND dTourDate and Status NOT LIKE Cancelled quer
  • 如何在索引视图中打印关联数据

    subjects this gt Subjects gt find all contain gt Users fields gt Users username Users email gt hydrate false gt toArray
  • 带单引号的 XPATH 查询[重复]

    这个问题在这里已经有答案了 有人知道如何解决这个问题吗 单引号让我陷入困境 nodes xml gt xpath item contains catalog Billy s Blogs title 我尝试以各种方式逃避它 但都抛出错误 no
  • Laravel Redis 配置

    我目前正在使用 Laravel 和 Redis 创建一个应用程序 几乎一切都工作正常 我按照文档中的说明扩展了身份验证 用户可以订阅 登录 注销 我可以创建内容 所有内容都存储在 Redis 中 但我有一个问题 我无法运行 php arti
  • 在同一服务器上的 2 个子域中安装 2 个 WordPress 时共享用户

    我有 2 个 WordPress 网站 位于 2 个不同的子域中 例如test1 abc com and test2 abc com 这两个网站都激活了 wp require 插件 只有登录用户才能看到该网站 我们想要创建一个系统 如果用户
  • 在 JAX-WS 中使用安全性的最佳实践是什么

    这是场景 我有一些需要保护的 Web 服务 JAX WS 目前 为了身份验证需求 我提供了额外的 SecurityWService 它为授权用户提供了一些需要在请求其他服务时描述的 userid 和 sessionid 使用一些java安全

随机推荐

  • 合作搜索优化算法(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 Matlab代码实现 4 参考文献 1 概述 合作搜索算法 CSA 在问题空间中随机生成
  • flutter-使用第三方库,编译和运行版本不一致问题 2

    问题 接着上一个问题 如果是继续有问题 你讲看到这篇文章 新的问题又出现啦 如 Command xx xx develop android flutter app android gradlew app properties Finishe
  • Anaconda切换python版本

    比如 我的 已经安装好了anaconda4 即已经有了python3 5 现在想切换3 7 安装3 7 命令行运行 前提是anaconda环境变量已经配置好 创建一个名为python37的环境 指定Python版本是3 7 conda会为我
  • Dictionary Learning(字典学习、稀疏表示以及其他)

    第一部分 字典学习以及稀疏表示的概要 字典学习 Dictionary Learning 和稀疏表示 Sparse Representation 在学术界的正式称谓应该是 稀疏字典学习 Sparse Dictionary Learning 该
  • js-JavaScript 对象

    1 对象定义 JavaScript 对象是拥有属性和方法的数据 2 格式 键值对 var person firstName John lastName Smith age 50 eyeColor blue move function ale
  • 后端Long型数据传给前端精度丢失问题 分布式id 解决方案

    Long型数据id传给前端精度丢失问题 数据库数据类型bigint 今天将文章类ArticleVo的数据传给前端时 发现前端接收的数据id不一样 如前端获得的id 1405916999732707300 但数据库里是id 140591699
  • springboot国际化message配置

    常常在需求中遇到国际化的要求 而国际化最常见的就是中英文切换 除了前端 后端也需要进行国际化处理 这里来记录一下我实现国际化的步骤代码 1 在resource下的i18n下建立messages properties messages en
  • CycleGAN和Conditional GAN(cGAN)

    当谈到CycleGAN和Conditional GAN cGAN 时 我们涉及到生成对抗网络 GAN 的不同变体 让我逐步介绍它们的原理和应用 CycleGAN CycleGAN是一种无监督的图像转换模型 它可以在两个不同的图像域之间进行转
  • Ubuntu Source Insight 4.0安装后首次打开报错

    系统为中文会出现 Unable to open or create 中文路径 sidb 参照网上修改regedit方法 发现没用 直接修改 wine drive c users server 我的文档 为 wine drive c user
  • C++ 中 map 容器的内存释放机制及内存碎片管理

    C 中 map 容器的内存释放机制及内存碎片管理 C 中的容器很好用 比如 vector map 等 可以动态扩容 自己管理内存 不用用户关心 但是在某些极端情况下 如果内存比较紧张的情况下 可能用户对于这些容器自己的管理规则 主要是释放规
  • Linux read命令

    读取n个字符存入变量 不用按回车 输入到第n个自动结束 student myhost read n 3 a 123 student myhost echo a 123 无回显方式读取密码 student myhost read s pass
  • windows spacemacs实现org-mode转latex,然后生成pdf

    spacemacs默认英文字体做如下修改 安装了完整版ctex套装 spacemacs增加layer gt latex 增加windows的path路径 解决org mode里中英文等宽问题 latex编译命令 pdf预览等 实现了org转
  • 什么是文件目录,文件目录项的主要内容是什么?

    文件目录是记录系统中所有文件的名字及其存放地址的目录表 表中还包括关于文件的说明信息和控制信息 主要内容如下 1 文件名 文件名分为文件的符号名和内部标识符 id号 2 文件的逻辑结构 说明该文件是否是定长 记录长度及记录个数等 3 文件的
  • USB如何布局走线

    1 先上图 USB分为2 0和3 0 2 USB布局走线需要注意的地方 静电防护 阻抗匹配 同组等长
  • cv::Mat遍历赋值的几种方式

    cv Mat赋值的几种方式 1 前言 2 Mat简介 3 遍历Mat赋值方式 方式一 方式二 方式三 4 测试 5 参考文献 1 前言 背景 获取传感器数据后需要保存成图片 有时需要对里面的元素进行操作 因为是自己开发 不能直接得到图片 所
  • CopyOnWriteArrayList部分源码分析

    CopyOnWriteArrayList部分源码分析 我们都知道ArrayList是基于数组实现的可动态扩容的集合 但是他实际上也是线程不安全的 而在JUC java util concurrent 下有个线程安全的数组集合 就是CopyO
  • django开发电子商城(四)django分页进阶和列表长度控制

    1 在list html中增加bootstrap分页代码 2 增加样式 使分页列表居中 3 修改views py文件 将分页数据传到前端 4 修改list html 根据传到前端的分页数据进行渲染分页条
  • 1035 插入与归并

    1035 插入与归并 根据维基百科的定义 插入排序是迭代算法 逐一获得输入数据 逐步产生有序的输出序列 每步迭代中 算法从输入序列中取出一元素 将之插入有序序列中正确的位置 如此迭代直到全部元素有序 归并排序进行如下迭代操作 首先将原始序列
  • python循环语句for 循环十次_python循环10次写法以及实例代码

    python循环10次怎么写 Python for循环可以遍历任何序列的项目 如一个列表或者一个字符串 语法 for循环的语法格式如下 for iterating var in sequence statements s 例子 for i
  • PHP 实现网页爬虫

    方法一 通过fopen和stream get contents获取html内容 从给定的url获取html内容 爬虫程序 原型 从给定的url获取html内容 通过fopen和stream get contents获取html内容 para