今日头条爬虫之:解析JS得到signature

  只要你开始写爬虫了,或早或晚的你都会去接触到JavaScript。然后等你爬虫做久了,你就会成为你个资深的前端开发工程师。
  在之前的文章中提过,在定向爬虫中极其不推荐使用selenium,速度太慢。那对于JavaScript总要有个解决方案,速度相对快的解决方案有两个:
将js代码翻译成python。严肃别笑,这是可行的,在js混淆不盛行的时候我真的这么干过。
第一你要非常有时间,毕竟你可能对js不熟。但JavaScript是每个前端工程,啊呸,爬虫工程师绕不过的南墙。
  在js混淆盛行的现在,反正我是不会选这个方法,你选你大佬,你可以站在爬虫鄙视链的顶端。
  略微分析,直接去执行有效的js代码,取得你想要的结果。
为什么说有效,因为现在的js里会混淆大量无效干扰你的js,比如极验。
JavaScript的执行需要js引擎,于是引入今天的主角PyV8。

Google V8 is Google’s open source JavaScript engine.
V8 is written in C++ and is used in Google Chrome, the open source browser from Google.
V8 implements ECMAScript as specified in ECMA-262, 3rd edition, and runs on Windows XP and Vista, Mac OS X 10.5 (Leopard), and Linux systems that use IA-32 or ARM processors.
V8 can run standalone, or can be embedded into any C++ application.

PyV8的安装:
pip install pyv8
  如果顺利的话就可以进行下面的步骤了,如果报错就需要根据你们自身的系统去谷歌一下解决方案,windows直接有.exe安装程序。Linux与MacOS需要安装对应依赖,在这不赘述,相信大家的找资料能力,实在解决不了可以私聊我,乐意效劳。

PyV8的使用:
  最好的文档肯定是官方文档,这里仅能给出几个我常用的,以及一些我的使用心得,以防大家踩坑。
import PyV8注意大小写。

PyV8.JSContext() 创建JSContext对象,因为有enter()方法,可以这样用
with PyV8.JSContext() as ctxt:
接下来就使用ctxt来执行js脚本,其使用方法多半有两种,涉及的关键属性是locals:

locals
Local variables within context

与JavaScript中变量交互(使用最多):
获得JavaScript中变量

import PyV8
with PyV8.JSContext() as ctxt:
    ctxt.eval("""
                var_ex1 = 1;
                var_ex2 = 1.0;
                var_ex3 = "test";
                var_ex4 = true;
            """)
    vars = ctxt.locals
    var_ex1 = vars.var_ex1
    print var_ex1

传入python中变量

import PyV8
with PyV8.JSContext() as ctxt:
    ctxt.locals.test = 12
    print int(ctxt.eval("test"))

与JavaScript中函数交互:

把Enc绑定到js中的Enc方法

Enc = ctxt.locals.Enc
#执行Enc方法,传入python的参数:params,_deskey,用python接受返回值
str = Enc(params, _deskey, '', '')

  其实大家也都看出来了,差别不大,其中核心目的都是为了执行JavaScript代码,写成哪种风格就纯属个人喜好了。

PyV8.JSLocker() 值得注意的是PyV8并非是线程安全的,因此在多线程环境下要加入全局锁。
  下面的代码也是第一点的另一种写法,显式的enter与退出,想必一看就懂。

ctxt = PyV8.JSContext()
with PyV8.JSLocker():
    self.ctxt.enter()
    vl5x = self.ctxt.eval(js) 
    self.ctxt.leave()

PyV8的实战:
  那说了不少,真正在爬虫中应该怎么用?下面给出本文福利,实战今日头条(破解反爬关键参数)。
  今日头条在一两个月前的更新中,在url中加入一个参数_signature,该参数是将参数user_id传入js后执行回传的。
  经过你的一番令人折服的操作(抓包、断点调试js),这是爬虫基本功,就不一个步骤一个步骤贴详细过程了。
  你找到目标js的地址:https://s3.pstatp.com/toutiao/resource/ntoutiao_web/page/profile/index_8f8a2fb.js(抓包)
  并分析出里面的的有效函数(断点调试js)
  user_id对你又是可见的。于是皆大欢喜,下面就可以实现计算_signature的代码了。

def get_signature(self,user_id):
   """
   计算_signature    
   :param user_id: user_id不需要计算,对用户可见
   :return: _signature
   """
   req = requests.Session()
   # js获取目的
   jsurl = 'https://s3.pstatp.com/toutiao/resource/ntoutiao_web/page/profile/index_8f8a2fb.js'
   resp = req.get(jsurl,headers = self.headers)
   js =  resp.content
   effect_js = js.split("Function")
   js = 'var navigator = {};\
           navigator["userAgent"] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36";\
        ' +  "Function" + effect_js[3] + 
             "Function" + effect_js[4] + 
        ";function result(){ return TAC.sign(" + user_id + ");} result();"
   # PyV8执行步骤
   with PyV8.JSLocker():
      self.ctxt.enter()  #已在上面初始化过
      vl5x = self.ctxt.eval(js) 
      self.ctxt.leave()
   self.LOG.info("圣诞快乐")

   return vl5x

  至此完成。将参数加上,就可以按照正常逻辑爬取今日头条了。
祝你早日成长为一个优秀的前端工程师,最后周末愉快~

在RedHat/CentOS下安装Docker(不升级内核)

由于内核版本问题,最初仅Ubuntu可以较好的支持Docker。不过,由于RedHat系列OS(REHL、CentOS)是目前主流的Linux服务器操作系统,所以令RedHat系列OS支持Docker很有必要。目前Docker和RedHat已经展开深入合作,并在2013年年底推出了可以在RedHat系列OS上运行的Docker0.7。

目前有一些博客介绍了如何在CentOS上安装Docker。但是这些博客都是针对老版本的Docker,安装方法是在升级操作系统内核版本的基础上完成。问题是,我们不可以随意升级生产环境的操作系统内核版本,而且Docker0.7的主旨就是:Docker使用者可以在不升级内核的前提下,在RedHat环境这使用Docker。因此,这里撰写一篇博客,介绍如何在RedHat/CentOS环境下,安装新版本的Docker。

一、禁用selinux
由于Selinux和LXC有冲突,所以需要禁用selinux。编辑/etc/selinux/config,设置两个关键变量。
SELINUX=disabled
SELINUXTYPE=targeted

二、配置Fedora EPEL源
1 sudo yum install http://ftp.riken.jp/Linux/fedora ... ease-6-8.noarch.rpm

三、添加hop5.repo源

cd /etc/yum.repos.d
sudo wget http://www.hop5.in/yum/el6/hop5.repo

四、安装Docker
sudo yum install docker-io

yum安装过程中,可以发现安装的软件只有docker和lxc相关包,没有内核包,例如kernel-ml-aufs。

五、初步验证docker
输入docker -h,如果有如下输出,就证明docker在形式上已经安装成功。

docker -h

Usage of docker:
-D=false: Enable debug mode
-H=[]: Multiple tcp://host:port or unix://path/to/socket to bind in daemon mode, single connection otherwise
-api-enable-cors=false: Enable CORS headers in the remote API
-b="": Attach containers to a pre-existing network bridge; use 'none' to disable container networking
-bip="": Use this CIDR notation address for the network bridge's IP, not compatible with -b
-d=false: Enable daemon mode
-dns=[]: Force docker to use specific DNS servers
-g="/var/lib/docker": Path to use as the root of the docker runtime
-icc=true: Enable inter-container communication
-ip="0.0.0.0": Default IP address to use when binding container ports
-iptables=true: Disable docker's addition of iptables rules
-p="/var/run/docker.pid": Path to use for daemon PID file
-r=true: Restart previously running containers
-s="": Force the docker runtime to use a specific storage driver
-v=false: Print version information and quit

六、手动挂载cgroup
在RedHat/CentOS环境中运行docker、lxc,需要手动重新挂载cgroup。
我们首选禁用cgroup对应服务cgconfig。
sudo service cgconfig stop # 关闭服务
sudo chkconfig cgconfig off # 取消开机启动

然后挂载cgroup,可以命令行挂载
mount -t cgroup none /cgroup # 仅本次有效

或者修改配置文件,编辑/etc/fstab,加入
none /cgroup cgroup defaults 0 0 # 开机后自动挂载,一直有效

七、调整lxc版本
Docker0.7默认使用的是lxc-0.9.0,该版本lxc在redhat上不能正常运行,需要调整lxc版本为lxc-0.7.5或者lxc-1.0.0Beta2。前者可以通过lxc网站(http://sourceforge.net/projects/lxc/files/lxc/)下载,后者需要在github上下载最新的lxc版本(https://github.com/lxc/lxc,目前版本是lxc-1.0.0Beta2)。
这里特别说明一点,由于Docker安装绝对路径/usr/bin/lxc-xxx调用lxc相关命令,所以需要将lxc-xxx安装到/usr/bin/目录下。

八、启动docker服务
sudo service docker start # 启动服务
sudo chkconfig docker on # 开机启动

九、试运行
sudo docker run -i -t Ubuntu /bin/echo hello world

初次执行此命令会先拉取镜像文件,耗费一定时间。最后应当输出hello world。

作者:speakingbaicai

Yummy\'s time has gone

大概在现在这样的季节不应该写一些伤春悲秋的玩意,可是既然开了头,那就多啰嗦两句好了.

最近在下班的公交车上经常能看到一些身着校服的孩子,很明显是去参加了某某补习班后拖着疲惫身子赶回家时的样子,这让我不由多了一些感慨,明天是高考的日子,我在若干年前也曾经经历过这样一段紧张又令人难忘的时期,现在想来那段时光真的是美好且愉悦的,如果只需要踌躇于函数式的求导`细胞的有丝分裂过程等诸如此类问题的话...

说到这里,突然发现我离开学校到步入社会也有一年的时间了,这一年里得到了一些,但是好像失去了更多,我没有时间去回忆匆匆而过的美好时光,当我投身进这个大熔炉时我首先想到的是如何不被淘汰掉,于是疯狂地做无关兴趣只关乎生存的事情,曾几何时我也有些自命不凡的抱负和希冀,现在看来不得不接受现实的残酷,本来就是个俗人,做些俗的事情无可厚非,况且值得让我庆幸的是我现在养活自己的手段也是我自愿并且喜欢做的事. 然后美好的时光就这样匆匆流过。每当想起这些,我就觉得沮丧。但有很多事,真的不是我能改变的。也许这一年有过太多抱怨,太多摇摆,为了获得,不断地放弃。有时候早上醒来,已经不知道自己有什么目标,是什么,让自己活下去。 大家都认为一个码代码的应该拥有纯理性的思维,这样才能保证写出优质的代码的同时尽量少地为自己或者后来维护的人挖坑.但往往事情却无这样的绝对.

从来英雄如美人,不许人间见白头.

在这条路上还能走多久,我不知道.我甚至不敢想,连触及一下的念头都没有,何时已经如此怯懦,我也不知道... 幼稚往往是一个人的常态,我也只能这样的安慰我自己,从这个角度来看,我也算是一个复杂的动物,嘴上一句带过心里却一直重复.

清末河北人郭云深曾因犯下命案入狱二十多年.郭老在牢里被戴上脚铐,行走不便,并且每次只能迈开半步,因此常人练崩拳需要前跨一步,而郭老只能跨半步.后来郭老名扬四海,以“半步崩拳打天下”著称. 我从这个故事得到的启发是环境不是限制人的先决条件,比如黑煤窑里的挖煤工,他们人人都有一副壮硕的身体. 这个圈子也一样,你进来时稚气未脱,现如今已初尝人世百态,你会看到以前落榜的同学已经走入社会,你参加同学会时会发现曾经交集颇深的人们已经分别走上了不同的生活轨迹,有些混迹官场,有些浪荡江湖,有些新婚燕尔,有些已经为人父母.

放眼全是熟悉人,开口却皆是新鲜事...

这个世界上还存在没有故事的人么? Yummy原是我为我妈妈的西点屋起的名字,我甚至为它做了一些VI设计,但是最后的结果是我的妈妈并没有用它,这让我有一些失落. so, Yummy's time has gone~

关于 | about

姓名:没技术  

@notech没技术
性别:男
E-MAIL:admin[at]notech.cc
80后 ,绝对宅.勉强算个技术宅.对硬件极痴迷,但是从事码农工作. 走在通往geek的道路上... 现就职新浪微博(weibo.com)
VPS位于Linode

关于此博

初衷是想写一些技术文章,好吧,初衷而已... 目前状况是原创内容:转载内容1:1,并且这个比值正在逐步缩小... 极度渴求友情链接中...

一个很不错的正则表达式分析工具

效果: 如图所示,可以将正则表达式转化成直观的图片.很不错,对于超长的正则表达式可以很直管的分析功能. 连接地址在 猛击这里!

一个自动更新google Host的bat脚本

最近不知道怎会回事,公司里的google上不了,这是何等蛋疼的事情啊. 网上搜索,有以为网友给出了一个更新host的bat,这里贴一下,留作以后备用 google_hosts.rar 双击运行,按指令即可更新,这样,google搜索再也不怕"链接被重置了"。 提醒:修改时,国内杀软可能会有警报,忽略即可,保证无毒的。亲测可用.

sphinxapi.php 的一些注释.

sphinxapi.php 的一些注释.和sphinx的配置以及一些常规命令.做备忘.

<?php 

include_once 'sphinxapi.php';
$s = new SphinxClient();
$s->setServer("localhost", 9312);
$s->SetConnectTimeout ( 1 );//设置链接超时


/*
$s->AddQuery();//列表查询
$s->RunQueries ();//执行列表查询
$s->ResetFilters();//清除过滤条件
$s->BuildExcerpts($docs, $index, $words);//生成简要
$s->BuildKeywords($query, $index, $hits);//生成关键字
$s->GetLastError();//错误
$s->GetLastWarning();//警告
$s->FlushAttributes();//索引刷入硬盘
$s->IsConnectError();//链接错误
$s->ResetGroupBy();//重设分组
$s->SetFieldWeights(array('sub_title'=>1));//加权最小为1
$s->SetIDRange($min, $max);//ID范围
$s->SetIndexWeights(array('test1'=>1));//索引权重
$s->Status();//服务是否可用
$s->UpdateAttributes($index, $attrs, $values);//更新硬盘索引
*/
/*
参考文档:http://www.coreseek.cn/docs/coreseek_4.1-sphinx_2.0.1-beta.html#matching-modes
SPH_MATCH_ALL, matches all query words (default mode);
SPH_MATCH_ANY, matches any of the query words;
SPH_MATCH_PHRASE, matches query as a phrase, requiring perfect match;
SPH_MATCH_BOOLEAN, matches query as a boolean expression (see Section 5.2, “Boolean query syntax”);
SPH_MATCH_EXTENDED, matches query as an expression in Sphinx internal query language (see Section 5.3, “Extended query syntax”). As of 0.9.9, this has been superceded by SPH_MATCH_EXTENDED2, providing additional functionality and better performance. The ident is retained for legacy application code that will continue to be compatible once Sphinx and its components, including the API, are upgraded.
SPH_MATCH_EXTENDED2, matches query using the second version of the Extended matching mode.
SPH_MATCH_FULLSCAN, m
*/
$s->setMatchMode(SPH_MATCH_ANY);//匹配模式
$s->setMaxQueryTime(3);//查询超时
//$s->SetSelect ( $select );//设置返回的字段
/*
$cl->SetSelect ( "*, @weight+(user_karma+ln(pageviews))*0.1 AS myweight" );
$cl->SetSelect ( "exp_years, salary_gbp*{$gbp_usd_rate} AS salary_usd,
   IF(age>40,1,0) AS over40" );
$cl->SetSelect ( "*, AVG(price) AS avgprice" );
 */

/*
$cl->SetGroupBy ( "category", SPH_GROUPBY_ATTR, "@count desc" );
$cl->SetGroupDistinct ( "vendor" );
==
SELECT id, weight, all-attributes,
    COUNT(DISTINCT vendor) AS @distinct,
    COUNT(*) AS @count
FROM products
GROUP BY category
ORDER BY @count DESC
*/
//$s->SetGroupBy ( $groupby, SPH_GROUPBY_ATTR, $groupsort );//汇总
//$s->SetGroupDistinct ( $distinct );//设置不重复字段

$s->SetArrayResult ( true );//结果是否有ID

/*
    SPH_SORT_RELEVANCE mode, that sorts by relevance in descending order (best matches first);
    SPH_SORT_ATTR_DESC mode, that sorts by an attribute in descending order (bigger attribute values first);
    SPH_SORT_ATTR_ASC mode, that sorts by an attribute in ascending order (smaller attribute values first);
    SPH_SORT_TIME_SEGMENTS mode, that sorts by time segments (last hour/day/week/month) in descending order, and then by relevance in descending order;
    SPH_SORT_EXTENDED mode, that sorts by SQL-like combination of columns in ASC/DESC order;
    SPH_SORT_EXPR mode, that sorts by an arithmetic expression.
 */
//$s->SetSortMode ( SPH_SORT_EXTENDED, $sortby );//排序模式

/*
$s->SetOverride($attrname, $attrtype, $values);
$s->ResetOverrides();*/
/*
$s->SetRetries($count);//设置失败重试
$s->SetRankingMode($ranker);//设置排名模式 均适用于SPH_MATCH_EXTENDED2搜索

//第3个参数当为true时,相当于$attribute!=$value,默认值是false
$s->SetFilter ( 'target_type', $filtervals );//设置过滤,值列表
$s->SetFilterFloatRange($attribute, $min, $max);//浮动范围
$s->SetFilterRange($attribute, $min, $max);//指定范围
$s->SetGeoAnchor($attrlat, $attrlong, $lat, $long);
*/
//link
//$s->SetFilter ( 'target_type', array(1),true );


$s->SetLimits ( 0, 10 );//显示数量:开始 量 最大量 右偏移量
$result = $s->query("good","team");//查询


print_r($result);

 

- 阅读剩余部分 -

关于MYSQL触发器

- 阅读剩余部分 -

处理wordpress在nginx上500错误一例

在nginx上做wordpress博客,如果你使用了wordpress自带的固定连接功能,那一定会涉及到修改rewrite的地方, 因为wordpress默认是修改仅apache支持的.htaccess的规则. 如果是nginx用户,通常会在conf/nginx.conf内添加如下:

- 阅读剩余部分 -

python学习笔记

2012-10-20 00:30 装了ubuntu12.10 AMD64,说实话Linux还是ubuntu用的顺手一些.

12.10装好以后默认就安装好了python.含有2.7.2和3.0以及3.3几个版本.

svn co http://code.djangoproject.com/svn/django/trunk djtrunk 通过SVN拿到最新的django版本

/usr/lib/python2.7/dist-packages 里加入django,pth指向djtrunk 目录

ln -s /path/to/django/bin/django-admin.py /usr/local/bin/django-admin.py 给django-admin.py做个快捷方式

随便进个目录,django-admin.py startproject 建立一个项目

值得一提的,py文件第一句加上#coding=utf8防止乱码

- 阅读剩余部分 -

Python3.x和Python2.x的区别

这个星期开始学习Python了,因为看的书都是基于Python2.x,而且我安装的是Python3.3,所以书上写的地方好多都不适用于Python3.3,特意搜索了一下3.x和2.x的区别。特此在自己的博客中记录一下,以备以后查找方便,也可以分享给想学习Python的friends. 以下内容来自于网络.继续阅读:http://wiki.python.org/moin/Python2orPython3   1.性能 Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可 以取得很好的优化结果。 Py3.1性能比Py2.5慢15%,还有很大的提升空间。

- 阅读剩余部分 -

挪威的森林

话说内容实在是有一些粗俗,所以各位还是直接看截图好了,粘贴会死~~

今晚晚餐

20121009-180717.jpg20121009-180804.jpg

Redis 安装配置

一,什么是redis redis是一个key-value存储系统。 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集 合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis 支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改 操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。 二,安装配置redis 1、下载源代码

http://code.google.com/p/redis/downloads/list

下载redis-1.2.6.tar.gz 将下载包拷贝到/usr/local/webserver/redis-1.2.6/下 2、安装

tar -zxvf redis-1.2.6.tar.gz
ce redis-1.2.6
make

- 阅读剩余部分 -

申请了新浪的开放平台.

不知道能不能通过,如果通过的话回头把自己的微博(http://t.notech.net)加上同步新浪微博功能.一切从新开始...