怎么利用PHP抓取百度阅读

 更新时间:2016年12月21日 21:07  点击:1356
最近在百度阅读上购买了一本《永恒的终结》电子书,但是坑爹的发现只能在线阅读或者在手机app上阅读,不能下载下来放到kindle里。于是就尝试一下看能不能把这个文章下载下来。有需要的朋友们可以参考借鉴,下面来一起看看吧。 这篇文章主要介绍的是,如何利用PHP抓取百度阅读的方法,下面话不多说,来一起看看吧。

抓取方法如下

首先在浏览器里打开阅读页面,查看源代码后发现小说的内容并不是直接写在页面里的,也就是说小说的内容是通过异步加载而来的。

于是将chrome的开发者工具切到network一栏,刷新阅读页面,主要关注的是XHR和script两个分类下。

经过排查,发现在script分类下有个jsonp请求比较像是小说内容,请求的地址是

http://wenku.baidu.com/content/49422a3769eae009581becba?m=8ed1dedb240b11bf0731336eff95093f&type=json&cn=1&_=1&t=1423309200&callback=wenku7

返回的是一个jsonp字符串,然后我发现,如果把地址里面的callback=wenku7去掉,返回的就是一个json字符串,这样解析起来就方便不少,可以直接在php里面转换成数组。

再来分析一下返回数据的结构,返回的json字符串之后是一个树状的结构,每个节点都有一个t属性和c属性,t属性用来指明这个节点的标签,比如h2 div等等,c属性就是内容了,但也有两种可能,一个是字符串,另一个是数组,数组的每个元素都是一个节点。

这种结构最好解析了,用一个递归就搞定

最终代码如下:

<?php

classBaiduYuedu {

 protected$bookId;

 protected$bookToken;

 protected$cookie;

 protected$result;

 publicfunction__construct($bookId,$bookToken,$cookie){

  $this->bookId =$bookId;

  $this->bookToken =$bookToken;

  $this->cookie =$cookie;

 }

 publicstaticfunctionparseNode($node){

  $str=''

  if(is_string($node['c'])){

   $str.=$node['c'];

  }elseif(is_array($node['c'])){

   foreach($node['c']as$d){

    $str.= self::parseNode($d);

   }

  }

  switch($node['t']){

   case'h2':

    $str.="\n\n";

    break;

   case'br':

   case'div':

   case'p':

    $str.="\n";

    break;

   case'img':

   case'span':

    break;

   case'obj':

    $tmp='('. self::parseNode($node['data'][0]) .')'

    $str.=str_replace("\n",'',$tmp);

    break;

   default:

    trigger_error('Unkown type:'.$node['t'], E_USER_WARNING);

    break;

  }

  return$str;

 }

 publicfunctionget($page= 1){

  echo"getting page {$page}...\n";

  $ch= curl_init();

  $url= sprintf('http://wenku.baidu.com/content/%s/?m=%s&type=json&cn=%d',$this->bookId,$this->token,$page);

  curl_setopt_array($ch,array(

   CURLOPT_URL   =>$url,

   CURLOPT_RETURNTRANSFER => 1,

   CURLOPT_HEADER   => 0,

   CURLOPT_HTTPHEADER  =>array('Cookie: '.$this->cookie)

  ));

  $ret= json_decode(curl_exec($ch), true);

  curl_close($ch);

  $str=''

  if(!empty($ret)){

   $str.= self::parseNode($ret);

   $str.=$this->get($page+ 1);

  }

  return$str;

 }

 publicfunctionstart(){

  $this->result =$this->get();

 }

 publicfunctiongetResult(){

  return$this->result;

 }

 publicfunctionsaveTo($path){

  if(empty($this->result)){

   trigger_error('Result is empty', E_USER_ERROR);

   return;

  }

  file_put_contents($path,$this->result);

  echo"save to {$path}\n";

 }

}

//使用示例

$yuedu=newBaiduYuedu(�a3769eae009581becba',Ǝed1dedb240b11bf0731336eff95093f','你的百度域cookie');

$yuedu->start();

$yuedu->saveTo('result.txt');


这个类前两个参数可以从小说的介绍页面获得,第一个参数bookId就是urlebook后面跟着的字符串,第二个参数bookToken在页面源代码搜索bdjsonUrlm参数后面的那个字符串就是。

注:如果不传入百度cookie或者百度cookie无效,则只能抓取免费阅读部分,要抓完整的内容必须保证cookie可以正常使用。

总结:

以上就是这篇文章的全部内容了,希望本文的内容对大家学习或者使用PHP能有一定的帮助,如果有疑问大家可以留言交流。

最近有个朋友问我,php中的use关键字是不是会进行文件的自动引入?其实use关键字与文件加载没有一点关系,use关键字的作用就是声明要使用的类所处那个命名空间之下。下面通过这篇文章跟着小编一起学习下PHP中的use关键字及文件的加载。

可能在大家经常使用框架,写一个Controller或者Model的时候,写了好多use,但是并没有写文件加载的代码,就以为use可以进行文件的自动加载了。

详细介绍

其实,现在流行的php框架,都是基于MVC模式的,大量的使用了命名空间,以提高程序的灵活性。那么框架是怎么实现将use关键字所声明的类库对应的脚本文件进行加载的那?

(1):在通过use关键字进行声明类库的声明的时候,并不会进行脚本的加载,而是在脚本文件真正使用到所对应的类库的时候才会进行加载(这就是所谓延迟加载)。

(2):框架一般在初始化阶段,就声明了__autoload()函数或者是spl_autoload_register()函数(一般会在入口文件中进行声明)。在调用通过use声明的类库的时候,会自动的调用上述的函数,将调用的类库名称传递到函数中(这里的类库名称是包括命名空间的全名称)

<?php
namespace Home\Controller;
function __autoload($class_name) { 
 //echo $class_name."<br/>"; 
 require_once ("./".$class_name . ".php");  
}
use Admin\Controller\Index;
new Index; //new Index会触发__autoload()函数,返回Admin\Controller\Index到函数中
?>

(3):框架中定义的__autoload()函数或者是spl_autoload_register()函数在接收到传递过来的类库名称以后,框架会对名称进行处理,分析出类库名称所对应的文件路径,然后进行文件的加载。这里需要注意的是,不同的框架在解析类库名称,分析文件路径的方式是各不一致的,毕竟各自的目录结构是不一样的。

比如说,thinkphp:

/**
  * 类库自动加载
  * @param string $class 对象类名
  * @return void
  */
 public static function autoload($class) {
  // 检查是否存在映射
  if(isset(self::$_map[$class])) {
   include self::$_map[$class];
  }elseif(false !== strpos($class,'\\')){
   $name   = strstr($class, '\\', true);
   if(in_array($name,array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$name)){ 
    // Library目录下面的命名空间自动定位
    $path  = LIB_PATH;
   }else{
    // 检测自定义命名空间 否则就以模块为命名空间
    $namespace = C('AUTOLOAD_NAMESPACE');
    $path  = isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH;
   }
   $filename  = $path . str_replace('\\', '/', $class) . EXT;
   if(is_file($filename)) {
    // Win环境下面严格区分大小写
    if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){
     return ;
    }
    include $filename;
   }
  }elseif (!C('APP_USE_NAMESPACE')) {
   // 自动加载的类库层
   foreach(explode(',',C('APP_AUTOLOAD_LAYER')) as $layer){
    if(substr($class,-strlen($layer))==$layer){
     if(require_cache(MODULE_PATH.$layer.'/'.$class.EXT)) {
      return ;
     }
    }   
   }
   // 根据自动加载路径设置进行尝试搜索
   foreach (explode(',',C('APP_AUTOLOAD_PATH')) as $path){
    if(import($path.'.'.$class))
     // 如果加载类成功则返回
     return ;
   }
  }
 }

这里只是举例说明use与文件的自动加载没有关系,不强调各个框架是具体怎么完成自动加载,具体的可以自己看框架代码进行研究。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

max_input_vars在php中一般默认就可以了但是有时会碰到max_input_vars设置导致php出问题了,下面我们来看一篇关于max_input_vars的解决办法吧.


今天接到客服部工作人员反馈的一个客户的问题,产品是允许用户添加一个产品属性的,而每个属性是由多个表单域组成 ,这样当每添加一个属性就等于添加了n个表单域,这个客户添加的非常的多,发现在提交保存的时候总是失败,提示其中一个表单元素的索引值不存在,经测试是发现服务端接收的一些表单域丢失了一部分。起初分析的是服务器接收的数据超出了php设置的max_post_size(其实当时已经设置了8M,足够使用了),修改了测试发现此问题仍然存在。后来将用户原来的一些添加的表单元素进行删除,再重新添加同样数据库表单域可以成功,但一旦超出一定数量的表单域就会发生丢失的情况,这个时候首先怀疑的是apache是否有类似限制接收隐藏域的指令,找了没有找到,紧接着在php中批到一个max_input_vars这个指令,意思就是说php中允许接收的最大表单域数据,到目前为止基本上是确定这个原因引起的了,奖其修改为2000,重启Apache,发现一切正常。

max_input_vars默认值为1000导致多表单提交失败

再看了下php-fpm的日志,有点信息可以参考了。


[25-Sep-2014 15:19:30] WARNING: [pool www] child 28329 said into stderr: "NOTICE: PHP message: PHP Warning:  Unknown: Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini. in Unknown on line 0"

提示input 变量个数超过1000,建议修改php.ini文件中的 max_input_vars,PHP从5.3.9开始增加一个变量 max_input_vars 用来限制提交的表单数量。

妈的,我这个功能(类似于phpmysqladmin功能,读取数据库表,然后能写入编辑,然后数据库字段有128个,然后每个字段有11个input框)大概有1400多个input,(多么痛的领悟,为毛这么吊,研发一个表搞这么多字段),

然后我在php.ini里面加入

max_execution_time = 30     ; Maximum execution time of each script, in seconds
max_input_time = 60     ; Maximum amount of time each script may spend parsing request data
max_input_vars = 2000

重启php-fpm后,功能正常了。看日志很重要。

总结:提起php中的max_input_vars 估计很少人知道这个这个指令,因为他的使用场景实在是太少了,在php.ini中这个指令的定义是指服务端最大可以接收的表单域的数量多少,默认是1000,这足够我们平时使用了。但仍然有一些特殊的情况下需要修改此值的大小。

PHP 写文件加锁有函数了这个可以保证文件同时多人操作时出现数据丢失的问题了,下面我们就一起来看看如何实现PHP 写文件加锁吧.

用 PHP 的 file_put_contents 函数以追加的方式,循环 10 w 次写文件,耗时很多。因为 file_put_contents 函数每次都要打开文件,写入文件,然后关闭文件。

以下是测试:

public function handle()
{
    $testTxt = storage_path('test.txt');
    for ($i = 0; $i < 100000; $i++) {
        $this->comment('writing...');
        file_put_contents($testTxt, 'wo shi tanteng.' . PHP_EOL, FILE_APPEND);
    }
    $this->comment('time:' . round(microtime(true) - LARAVEL_START, 2));
}
如图所示:


耗时 165.76 秒。现在换一种写文件的方式,使用 fwrite 并且加锁的方式同样循环 10w 次写入,代码如下:

public function handle()
{
    $testTxt = storage_path('test2.txt');
    $handle = fopen($testTxt, 'wr');
    flock($handle, LOCK_EX | LOCK_NB);
    for ($i = 0; $i < 100000; $i++) {
        $this->comment('writing...');
        fwrite($handle, 'wo shi tanteng.' . PHP_EOL);
    }
    flock($handle, LOCK_UN);
    fclose($handle);
    $this->comment('time:' . round(microtime(true) - LARAVEL_START, 2));
}
运行效果如图:


如图所示,耗时 40.46 s,大大提高了效率。

跟 file_put_contents 函数比, fwrite 提高了写文件的效率,同时使用 flock 进行写文件加锁,防止并发同时操作一个文件。

[!--infotagslink--]

相关文章

  • 百度网盟和google网盟推广那种效果好

    专做了百度和google的网盟推广以作推广效果的评估比较。百度的周期为6天,google为4天。   从百度的统计数据可以看出这六天的点击次数总共为464,平均点击花费了0.30元...2017-07-06
  • 源码分析系列之json_encode()如何转化一个对象

    这篇文章主要介绍了源码分析系列之json_encode()如何转化一个对象,对json_encode()感兴趣的同学,可以参考下...2021-04-22
  • php中去除文字内容中所有html代码

    PHP去除html、css样式、js格式的方法很多,但发现,它们基本都有一个弊端:空格往往清除不了 经过不断的研究,最终找到了一个理想的去除html包括空格css样式、js 的PHP函数。...2013-08-02
  • index.php怎么打开?如何打开index.php?

    index.php怎么打开?初学者可能不知道如何打开index.php,不会的同学可以参考一下本篇教程 打开编辑:右键->打开方式->经文本方式打开打开运行:首先你要有个支持运行PH...2017-07-06
  • PHP中func_get_args(),func_get_arg(),func_num_args()的区别

    复制代码 代码如下:<?php function jb51(){ print_r(func_get_args()); echo "<br>"; echo func_get_arg(1); echo "<br>"; echo func_num_args(); } jb51("www","j...2013-10-04
  • 如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)

    以下是使用js代码实现百度地图计算两地距离,代码如下所示:<script src="js/jquery-1.9.0.js" type="text/javascript" language="javascript"></script><script language="javascript" type="text/javascript" src="js/...2015-10-30
  • PHP编程 SSO详细介绍及简单实例

    这篇文章主要介绍了PHP编程 SSO详细介绍及简单实例的相关资料,这里介绍了三种模式跨子域单点登陆、完全跨单点域登陆、站群共享身份认证,需要的朋友可以参考下...2017-01-25
  • 百度联盟封号了解封申请攻略

    百度联盟封号对于许多的站长来说肯定是会影响到心情的,那么既然是百度联盟封号了我们就肯定有一些原因的,虽然不是你自己搞的或一些其它因素都有可能,我们下面整理一下百...2016-10-10
  • PHP实现创建以太坊钱包转账等功能

    这篇文章主要介绍了PHP实现创建以太坊钱包转账等功能,对以太坊感兴趣的同学,可以参考下...2021-04-20
  • 基于JavaScript实现高德地图和百度地图提取行政区边界经纬度坐标

    本文给大家介绍javascript实现高德地图和百度地图提取行政区边界经纬度坐标的相关知识,本文实用性非常高,代码简单易懂,需要的朋友参考下吧...2016-01-24
  • php微信公众账号开发之五个坑(二)

    这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-02
  • 网站被百度拔毛 一月重新回归经验分离

    网站被K后,笔者做的第一件事便是在网站上增加更新模块。百度算法更新,对于网站内容给予了相当大的权重,这是笔者网站最欠缺的部分,保证了及时的更新便有了吸引蜘蛛爬取的...2016-10-10
  • ThinkPHP使用心得分享-ThinkPHP + Ajax 实现2级联动下拉菜单

    首先是数据库的设计。分类表叫cate.我做的是分类数据的二级联动,数据需要的字段有:id,name(中文名),pid(父id). 父id的设置: 若数据没有上一级,则父id为0,若有上级,则父id为上一级的id。数据库有内容后,就可以开始写代码,进...2014-05-31
  • PHP如何通过date() 函数格式化显示时间

    这篇文章主要介绍了PHP如何通过date() 函数格式化显示时间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-13
  • 如何用PS将百度熊抱枕做成大头枕?

    我们知道百度熊抱枕很大,只想要百度熊的大头,该怎么办呢?下面我们就来看看详细的教程。 1、首先打开photoshopCS6软件,新建一个“1600*1600”的白色背景图,并从右上角...2016-12-31
  • PHP+jQuery+Ajax实现多图片上传效果

    今天我给大家分享的是在不刷新页面的前提下,使用PHP+jQuery+Ajax实现多图片上传的效果。用户只需要点击选择要上传的图片,然后图片自动上传到服务器上并展示在页面上。...2015-03-15
  • 如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)

    以下是使用js代码实现百度地图计算两地距离,代码如下所示:<script src="js/jquery-1.9.0.js" type="text/javascript" language="javascript"></script><script language="javascript" type="text/javascript" src="js/...2015-10-30
  • 怎么对百度网页搜索的检索指标进行评估

    用户为满足自己某种需求而来到搜索引擎的,判断用户的需求是做好网站的开始。只有准确地判断出用户需求,了解用户搜索的目的,才能合理地衡量出一个网站结果的质量好,做好搜...2016-10-10
  • golang与php实现计算两个经纬度之间距离的方法

    这篇文章主要介绍了golang与php实现计算两个经纬度之间距离的方法,结合实例形式对比分析了Go语言与php进行经纬度计算的相关数学运算技巧,需要的朋友可以参考下...2016-07-29
  • PHP正则表达式过滤html标签属性(DEMO)

    这篇文章主要介绍了PHP正则表达式过滤html标签属性的相关内容,实用性非常,感兴趣的朋友参考下吧...2016-05-06