Python

用Python抓取QQ空间文章(终)

其实上一篇博文就已经将所有抓取工作解决了,这篇主要是抓取后的一点点处理工作(其实也没有处理完,充其量是个半成品)。 上篇说道使用正则表达式来匹配图片地址,不过上次方案有些缺陷,那就是疼迅给每张图片都加了链接,因此直接匹配会得到很多重复的地址,不过没关系,Python里有个很好用的模块:HTMLParser(Python 3是html.parser)。 文档上有个使用的例子: from HTMLParser import HTMLParser class MyHTMLParser(HTMLParser): def handle_starttag(self, tag, attrs): print "Encountered the beginning of a %s tag" % tag def handle_endtag(self, tag): print "Encountered the end of a %s tag" % tag 很明显的,handle_starttag方法在遇到开始标签时会被调用,而handle_endtag会在遇到结束标签时被调用,所以用HTMLParser结合正则表达式来获取图片地址就很方便了: def handle_starttag(self, tag, attrs): if tag == 'img': pattern = u"http://bd*.photo.store.qq.com/[^"]*" #图片地址 prog = re.compile(pattern); imgUrl = re.findall(prog, self.get_starttag_text()) if imgUrl: self.imgList.extend(imgUrl) 当然不是只定义这样一个方法就行了,使用HTMLParser需要创建自己的类,并继承HTMLParser: class PicParser(HTMLParser): 使用时只需要生成一个PicParser对象,并将网页内容作为参数调用其feed方法即可: picParser = PicParser() picParser.

用Python抓取QQ空间文章(2)

之前写过一篇文章简单说明如何用Python抓取QQ空间的文章,当时的脚本有两个缺陷:1.没有保存日志图片 2.未能获取日志发布时间。 当然原有的脚本还是可以使用的,今天对其进行了修改,改进了上面两个缺陷。 前篇文章说,未能获取日志发布时间的原因是文章是从简版抓取下来的,因此要想获取精确时间,就必须找到完整的日志地址。 在HttpFox的帮助下,地址并不难找: http://b1.cnc.qzone.qq.com/cgi-bin/blognew/blog_output_data?uin=QQ号码&blogid=文章ID 当然前面的二级地址与网络条件有关。这个地址就是真正的日志地址。只要将上次的脚本进行小幅修改,就可以抓取日志的内容了。 接着要保存图片。 这里只考虑保存在QQ空间相册里的图片,其他图床的情况较复杂,有兴趣的同学可以自行分析。 既然是保存在QQ空间相册中的图片,域名自然是QQ的,但是QQ的图片域名并没有后缀,而是像下面这样: http://b214.photo.store.qq.com/psu?/28499588-e936-4ad1-9d29-8048ecba8c54/TynjoQTxqQWMDDZ43wMDg7x2EemJeXmuQRkFtZ4S7qY!/b/YUAUnX.eAQAAYlIImn99AQAA 上面这个是近期日志的图片地址,下面这个是之前日志的图片地址: http://b210.photo.store.qq.com/http_imgload.cgi?/rurl4_b=d43765322eef1b64785ae3ab1f68a8a7e8f3cd5f08244b76a9981b6e6a62e0f81f601ece0421fac90b29f6c18bb5ea2839f18d666a3069bf880fd98a97d8e857ade443f4479c3719504d07c2033c4ff3e0fcfde6&a=210&b=210 好在腾讯似乎没有做太多的防盗链,也就是说,直接复制上面的地址到浏览器,是可以直接打开的,并且图片的URL只是后面有变化。因此图片地址的正则表达式也就很好写了: http://bd*.photo.store.qq.com/[^"]* 但是因为这个URL是看不出后缀的,因此需要获取MIME类型并判断图片后缀: imgInfo = urllib2.urlopen(image).info() #获取图片信息 这样可以获取图片的所有相关信息,得到的是一个字典类型变量,其中的”Content-Type”项就保存了图片的MIME类型,通过对MIME字符串进行处理,就可以得到图片的后缀。 剩下的就是保存图片的工作了,与保存网页相同,不再赘述。 更新后的代码仍然托管在bitbucket:http://goo.gl/vTNL1。 至此,所有抓取的工作就完成了,剩下的就是对已抓取的内容进行处理,提取日志内容和评论。

配置Django的Vim补全(使用Pydiction)

如今Django已经有不少好用的IDE,不过IDE写起代码来总不够流畅,因此还是希望使用Vim来写Django程序。 但是一想到Django一大堆Field,没有代码提示还是非常难过的。 网上解决的方法大多是使用PySmell,不过那东西需要安装,不够绿色环保,而且速度也实在不快,几经搜索,在万能的StackOverflow找到一种使用Pydiction进行补全的方法。 首先自然要安装Pydiction,不赘述,详情可以请教谷歌。 Pydiction使用的是字典补全,默认的字典包括了Python自带的包,因此想要补全Django就需要生成Django的字典。 不过在生成Django字典需要进行一些设置,不然会生成失败。原因是Django的一些模块依赖于项目的setting。 先用django-admin.py生成一个Django项目 接着配置环境变量 Linux: export DJANGO_SETTINGS_MODULE=settings export PYTHONPATH=/path/to/parent/of/settings Windows(未测试): DJANGO_SETTINGS_MODULE=settings ::这个就是需要import的包 set PYTHONPATH=%CD%/project/;%PYTHONPATH% ::将刚才生成的project目录路径加入到PYTHONPATH中 然后在项目目录下使用 python pydiction.py django django.conf django.contrib django.core django.db django.dispatch django.forms django.http django.middleware django.shortuts django.template django.templatetags django.utils django.views 创建Django字典(如果把原字典放在该目录下则可以添加到原字典的头面) 以上是网上搜索到的,不过只是这样还是不能补全XXXField,因为上面的目录不包含XXXField的定义。 执行 python pydiction.py django.db.models 即可创建models的字典。 以此类推,如果还有哪个模块不能补全,就这样生成模块字典即可。 配置好Pydiction,就可以补全Django啦~

用Python抓取QQ空间文章(1)

今天找了点时间看了点Python抓站的教程,便想把自己QQ空间的文章抓下来。 一开始想要直接抓站,可是QQ空间满是javascript一时让我无从下手,于是暂时作罢。 其实QQ空间还有一个掌上设备的版本, http://qz.qq.com ,这个版本的主页没有使用javascript(但是有些不便的地方,这个之后再说)。 简单分析了一下它的url,因为是面向掌上设备的版本,因此url并不复杂,文章列表的url的基本格式为: http://qz.qq.com/你的QQ号/bloglist?page=页码 而文章url的基本格式为: http://qz.qq.com/你的QQ号/blog?uin=你的QQ号&vin=0或者你的QQ号&blogid=文章ID 上面url中“0或者你的QQ号”取决与你是否登录,未登录就是0,登陆后就是你的QQ号(猜测)。 需要注意的是,最后的文章ID有两种,一般最近几年发表的日志都是10位数字,而几年前发表的日志则是从1开始的数字,例如,如果你昨天发表了一篇日志,你的url看上去是这样的(假设你的QQ号是10000,且未登录): http://qz.qq.com/10000/blog?uin=10000&vin=0&blogid=1234567890 而你几年前发表的日志的url看上去则是这样的: http://qz.qq.com/10000/blog?uin=10000&vin=0&blogid=12 因为这个问题让我郁闷了一会。。。 知道了这些剩下的工作就可以交给我们的Python了,根据 http://goo.gl/IMPOH 和 http://goo.gl/IfRJn 这两篇文章的说明,使用urllib2包进行抓站操作,花了两个小时的时间,就有了这样一个非常笨拙的代码: http://goo.gl/vTNL1。 目前还处在非常原始的状态,只能机械的将抓到的站保存为html文件,而且因为css神马的都在服务器上没有下载下来,所以打开的时候必须要联网。。。不过这些都不是主要问题,我抓站的主要目的是提取其中的文章与评论。 前面说过qz.qq.com有个不便的地方,那就是日志的时间显示不是精确时间,而是“两年前”,“三年前”这样的时间,因此抓下来的文章没法转换为我需要的格式,等我用firebug找到完整版日志的地址之后,再继续更新抓站程序吧(偷个懒都不行,腾讯你。。。)。

使用PHP空间为GAE做反向代理

不知道有多少喜欢GAE和Python的人。 众所周知的,GAE已经打不开了,而用于绑定域名的ghs(.)google(.)com也早就被那啥了,因此现在想要给GAE绑定域名必须通过反向代理。 网上关于用VPS来做GAE反向代理的教程有很多,我就不重提了,有VPS的朋友可以参照网上的教程。然而对与我这种穷人,VPS的价格实在让我无法承受,而用VPS专门为GAE做反向代理也有些大材小用的感觉。 在一番搜索之下,终于让我找到一个用PHP空间来为GAE做反向代理的程序。 点此下载:goo.gl/wuagz 下载后打开config.php,照下面的格式修改,上传到空间里去。 $adomain = array('GAE域名','你的域名'); //不要http:// 然后将你的域名绑定到免费空间上,就完成了。

Python首页出现中文下载链接

最近上v2ex的时候看见有人说Python官网出现了中文的下载链接,看了一下还真是。 大家都知道Python的download页面是打不开的,而中文的下载页面是指向http://www.python.org/getit/ [python.org]的,难道这是Python为中国广大用户着想的产物? 果然,在邮件列表里,有人说道: 地址:[https://svn.python.org/www/trunk/beta.python.org/build/data/content.ht](https://svn.python.org/www/trunk/beta.python.org/build/data/content.ht) [svn.python.org] r13591 | georg.brandl | 2011-01-25 05:36:13 +0800 (Tue, 25 Jan 2011) | 1 line Changed paths: M /trunk/beta.python.org/build/data/content.ht Add Chinese-language download link leading to the alias /getit that is not blocked by the Great Firewall of China. 感谢Python官网。。。

PythonChallenge解答:02

进入第二题。 页面上有一副图,上面是一本书: 下面还有一行小字(好吧其实不算小): recognize the characters. maybe they are in the book, but MAYBE they are in the page source. 既然提示我们在页面源代码里,那我们就打开它的源代码看看: 果然在其中发现了题目: find rare characters in the mess below: 然后是一串乱七八糟的符号。 那么这题目就很明确了,找出这一堆乱七八糟东西里面出现次数很少的字母。 关于这个rare网上有很多种理解,这里我理解为次数最少的,不过怎么理解对答案没有影响。 贴出我的解答: #coding:utf-8 ''' Created on 2011-1-21 @author: Jairie PythonChallenge02: ocr recognize the characters. maybe they are in the book, but MAYBE they are in the page source. ''' if __name__ == '__main__': str = '''字符略。太长了。 ''' myDict = dict() for word in str: myDict[word] = myDict.

推荐一个很有意思的网站:PythonChallenge

PythonChallenge(http://www.pythonchallenge.com/index.php [pythonchallenge.com])是一个非常有意思的网站,顾名思义,是用Python语言来解决一系列问题的网站,当然不一定非得用Python来解决,不过用Python一定能得到非常愉悦的体验(至少我这么觉得)。 打开网站后看到如下图的界面: 首页确实不好看。。。。咳咳,我们要看他的内涵。。。 把网页往下拖些,就看到题目入口了: 进入的是第0题: 第0题还是非常简单的,后面的题目就不那么简单了。。。。 这网站要求对Python的库比较熟悉,对于我这个只会基础语法的人来说就有点头大了。。。(寒假继续深造。。。) 另外每一题都有hint,不一定出现在页面正文处,标题,源代码都可能有。 早上花了点时间做了几题,确实很有意思。 有兴趣的童鞋欢迎和我一起讨论解法哈~

【转】GAE-管理Python应用程序的常用命令

App Engine Python SDK 含有用于和 App Engine 交互的名为 appcfg.py 的命令。可使用该命令将您的应用程序的新版本代码、配置和静态文件上传到 App Engine。还可使用该命令来管理数据存储区索引以及下载日志数据。 上传应用程序 要上传应用程序文件,请使用 update 操作并输入应用程序根目录的名称来运行 appcfg.py 命令。根目录应包含应用程序的 app.yaml 文件。 appcfg.py update myapp/ appcfg.py 将从 app.yaml 文件获得应用程序 ID,并提示您输入 Google 帐户的电子邮件地址和密码。使用您的帐户成功登录后,appcfg.py 会存储一个“cookie”,这样以后登录时就无需再提示输入密码。 您可以使用 –email 选项在命令行指定电子邮件地址。您不能将密码指定为命令行选项。 appcfg.py --email=Albert.Johnson@example.com update myapp/ 更新索引 当您使用 appcfg.py update 上传应用程序时,更新将包括应用程序的 index.yaml 文件。如果 index.yaml 文件定义了 App Engine 上还不存在的索引,则 App Engine 将创建此新索引。创建索引可能需要一些时间,时间长短取决于数据存储区中已存在的需要编入新索引的数据量。如果应用程序执行需要索引的查询但该索引还未构建完成,则该查询将引发异常。 要防止出现该问题,您必须确保在索引构建完成之前,要求新索引的应用程序的新版本不是应用程序的活动版本。其中一种做法是,每当您在 index.yaml 中添加或更改索引时,即在 app.yaml 中为应用程序指定一个新版本号。应用程序将以新版本上传,不会自动变成默认的版本。当您的索引已完成构建时,可使用管理控制台的“版本”部分将默认版本更改为新版本。 确保新索引在新的应用程序启用之前已构建的另一种方法是,在上传应用程序之前单独上传 index.yaml 配置。要仅上传应用程序的索引配置,请使用以下命令: appcfg.py update_indexes myapp/ 可从管理控制台的“索引”部分检查应用程序索引的状态。 删除不使用的索引 当您从 index.

Learning Python Chapter 4 备忘笔记

In Python 2.6, a backquotes expression X works the same as repr(X) and converts objects to display strings. Due to its obscurity, this expression is removed in Python 3.0; use the more readable str and repr built-in functions, described in “Numeric Display Formats” on page 115. 在Python2.6中,后引号表达式X与repr(X)的作用形同,将对象转换为字符串。因为其表意不明,这个表达式在Python3.0中被移除;因此使用更易读的内建函数str和repr来代替他。 The X // Y floor division expression always truncates fractional remainders in both Python 2.6 and 3.0. The X / Y expression performs true division in 3.

Python的迭代器和简单生成器(表达式)

今天在看《Python核心编程》,看到python中比较有趣的东西:迭代器和生成器表达式。 迭代器倒不是很稀奇,C++中就有,不过我也没用过,从我的理解中一直把迭代器当作指针的说。 不过那书里写的真不是很清楚,我就去求助了谷歌,找到下面一段(来自IBM): **由于迭代器比较容易理解,让我们先来看它。基本上, 迭代器是含有 **_**.next()**_** 方法的对象。唔,这样定义不十分正确,但非常接近。事实上,当迭代器应用新的 **_**iter()**_** 内置函数时,大多数迭代器的上下文希望得到一个可以生成迭代器的对象。为使用户定义的类(该类含有必不可少的 **_**.next()**_** 方法)返回迭代器,需要使 **_**__iter__()**_** 方法返回 **_**self**_** 。本文中的示例会清楚地说明这一点。如果迭代有一个逻辑终止,则迭代器的 **_**.next()**_** 方法可能决定抛出 **_**StopIteration**__** 异常。** _ 确实和指针差不多(吧?),不过这指针在调用后会自动指向下一个对象(我这样理解对不?) 这个生成器我就没接触过了,书中也没详细说明,于是继续谷歌: _**生成器要稍微复杂和一般化一点。但生成器最典型的用途是用来定义迭代器;所以不值得总是为一些细微之处而担心。 **生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。 _ 原来是这样,这玩意挺神奇。 在来看看《Python核心编程》里是怎么说的: _生成器表达式在 Python 2.4 被引入, 它与列表解析非常相似,而且它们的基本语法基本相同; 不过它并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这 个条目“产生”(yield)出来. 生成器表达式使用了”延迟计算”(lazy evaluation), 所以它在使用 内存上更有效. 我们来看看它和列表解析到底有多相似: _ _列表解析: _ _ _ _生成器表达式: (expr for iter_var in iterable if cond_expr) _ 然后在课后习题中: 8–7. 全数. 完全数被定义为这样的数字: 它的约数(不包括它自己)之和为它本身. 例如: 6 的约数是 1, 2, 3, 因为 1 + 2 + 3 = 6 , 所以 6 被认为是一个完全数.