虾米自动签到的python脚本

一个练手的小脚本,暂时只是实现了签到,还没有很完备的错误处理,而且在实现“全自动签到”上还没有想出什么合理的方案,先把代码贴上现丑了……

使用方法很简单

python xiami_auto_checkin.py email password

即把用户名(email)和密码作为参数传进去即可
如果你只是签固定的一个帐号,也可以直接将代码中的读参数改成赋值

这个代码只是最初的版本,你可以在这里看到最新的进展

#!/usr/bin/python
# encoding:utf-8

import re
import sys
import urllib
import urllib2
import cookielib

def check(response):
    """
    docstring for check
    """
    pattern = re.compile(r'<div class="idh">(已连续签到\d+天)</div>')
    result = pattern.search(response)
    if result: return result.group(1)
    return False
    pass

def main():
    """
    docstring for main
    """

    # Get email and password
    if len(sys.argv) != 3:
        print '[Error] Please input email & password as sys.argv!'
        return
    email = sys.argv[1]
    password = sys.argv[2]

    # Init
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
    urllib2.install_opener(opener)

    # Login
    login_url = 'http://www.xiami.com/web/login'
    login_data = urllib.urlencode({'email':email, 'password':password, 'LoginButton':'登陆',})
    login_headers = {'Referer':'http://www.xiami.com/web/login', 'User-Agent':'Opera/9.60',}
    login_request = urllib2.Request(login_url, login_data, login_headers)
    login_response = urllib2.urlopen(login_request).read()

    # Checkin
    checkin_pattern = re.compile(r'<a class="check_in" href="(.*?)">')
    checkin_result = checkin_pattern.search(login_response)
    if not checkin_result:
        # Checkin Already | Login Failed
        result = check(login_response)
        if result :
            print '[Succeed] Checkin Already!', email, result
        else:
            print '[Error] Login Failed!'
        return
    checkin_url = 'http://www.xiami.com' + checkin_result.group(1)
    checkin_headers = {'Referer':'http://www.xiami.com/web', 'User-Agent':'Opera/9.60',}
    checkin_request = urllib2.Request(checkin_url, None, checkin_headers)
    checkin_response = urllib2.urlopen(checkin_request).read()

    # Result
    result = check(checkin_response)
    if result:
        print '[Succeed] Checkin Succeed!', email, result
    else:
        print '[Error] Checkin Failed!'
    pass

if __name__=='__main__':
    main()

有任何问题,欢迎批评指正,更多更新信息,请参见这里

用Python处理xml文件中的非法字符

用xml.dom.minidom.parse()解析xml文件时遇到非法字符直接报错的问题
最后的方案是把纯文本方式读入文件,然后用字符串来处理
可以得到将非法字符全部剔除的结果

#!/usr/bin/python
# -*- coding:utf-8 -*-

import string
import xml.dom.minidom

def parse_xml(file_path):
    """
    Handle xml file with invalid character
    [input] : path of the xml file
    [output] : xml.dom.minidom.Document instance
    """
    try:
        xmldoc = xml.dom.minidom.parse(file_path)
    except:
        f = file(file_path)
        s = f.read()
        f.close()

        ss = s.translate(None, string.printable)
        s = s.translate(None, ss)

        xmldoc = xml.dom.minidom.parseString(s)
    return xmldoc

if __name__ == '__main__':
    pass

P.S. 如果有更好的解决方案,欢迎交流

在Eclipse中运行pdfbox

【前言】pdfbox是实验室做文档识别需要了解的开源项目,可是官网doc过于简略,网上资料很多只是调用jar并非在Eclipse中配置运行源代码,仅以此文祭奠我两天的折腾时间……

0) Environment Specification
OS:Windows 7
IDE:Eclipse SDK 3.7.0
JDK:Version 6 Update 26

1) This post will not involve the configuration of Java, but you need to confirm JAVA_HOME is in your “Environment Variable” which we will need later on.
The key should be “JAVA_HOME” and the value is the path of JDK, for me is “D:\Program Files\Java\jdk1.6.0_26″

2) Download and extract pdfbox, pdfbox-*.*.*-src.zip, for me is “pdfbox-1.6.0-src.zip” and the extact location is “E:\Code\JAVA\pdfbox-1.6.0″
http://pdfbox.apache.org/download.html

3) Download and Extract Maven2, apache-maven-*.*.*-bin.zip, for me is “apache-maven-3.0.3-bin.zip” and the extract location is “D:\Program Files\apache-maven-3.0.3″
http://maven.apache.org/download.html

4) Configure the “Environment Variable” for Maven2 / Install Maven2
4.1) Add key “M2_HOME” and the value is path you extact Maven2, for me is “D:\Program iles\apache-maven-3.0.3″
4.2) Add “%M2_HOME%\bin” to the key “Path”.
4.3) Open a new command prompt and run “mvn –version” to verify correct installation.

5) Install and configure the pdfbox via Maven2
5.1) Open a new command prompt and change directory to the extract location of pdfbox
5.2) Run “mvn clean install” to install the pdfbox
5.3) Run “mvn eclipse:eclipse” to make it a eclipse project.
5.4) Run “mvn -Declipse.workspace=”PATH OF THE WORKSPACE” eclipse:configure-workspace” to add M2_REPO classpath variable to Eclipse.
Note : 5.3 & 5.4 is the MOST IMPORTANT part.

6) Import the project into Eclipse with the root directory of pdfbox (for me is E:\Code\JAVA\pdfbox-1.6.0) then there should be no errors in all the projects.

7) Edit the “Run Configurations” and enter the command line arguments in the “Arguments” tab and then everything should run correctly.

Reference:
1) http://pdfbox.apache.org/userguide/building_pdfbox.html
2) http://maven.apache.org/download.html#Installation
3) http://maven.apache.org/guides/getting-started/index.html
4) http://www.mkyong.com/maven/how-to-configure-m2_repo-variable-in-eclipse-ide/

利用Python解析新浪博客javascript生成的评论

【前言】sina2wordpress终于有一个大概模样了,目前版本号为0.1
这是本站项目地址这是代码托管地址

言归正传,目前新浪博客的评论是用JavaScript生成的,直接用urllib2读取的信息中没有评论信息

通过Firefox下的firebug或者Chrome自带的Develop Tools,都可以找到js脚本在运行时GET的数据,具体方法是:打开之后选择“Network”标签,并选择“XHR”分类项,刷新页面并等待加载完成,稍等一会就会看到GET了一条以“comment”开头的html页面。

主要规律是,例如韩寒同学的这篇日志地址是 “http://blog.sina.com.cn/s/blog_4701280b0101854o.html”,那么打开日志页面时GET的就会是 “comment_4701280b0101854o_1.html”,规律不难发现,后面的那个数字就是评论的页数,最后的那个页数可以变为任意整数(没有尝试过上限),当超过实际评论页数时,显示的会是同样的编码,这也就是循环结束条件

此地址为相对路径,打开后是一堆乱码,这就是JavaScript的数据存储形式——json编码。可以简单的类比成Python中的字典,本例中共有两个关键字,一个是“Code”,对应值”A00006″,没发现啥用处,第二个关键字是“data”,其余部分均为data的对应值,利用Python的json模块进行解析可以发现,这就是评论的html代码。不过这里需要注意的是,第二个关键字“data”缺少双引号,直接解析会报错,需要先进行字符串处理,然后再解析。

相关代码如下(完整代码可以参见前言中的代码托管地址):

#根据json解析之后的html代码总结出来的各个关键信息的正则表达式
comment_author_pattern=re.compile(r'<span class="SG_revert_Tit".*?>(.*?)</span>')
comment_url_pattern=re.compile(r'<a href="(.*?)" target="_blank">(.*?)</a>')
comment_time_pattern=re.compile(r'<em class="SG_txtc">(.*?)</em>')
comment_content_pattern=re.compile(r'<div class="SG_revert_Inner SG_txtb".*?>(.*?)</div>', re.S) #这里的re.S很重要

def commentsAnalyze(key): #key为地址中间的标识性字符串
    num=1 #表示评论的页数
    url=r'http://blog.sina.com.cn/s/comment_%s_%d.html' %(key, num) #生成json编码对应的地址
    page=urllib2.urlopen(url).read().replace('data:','\"data\":',1) #给data添加双引号
    while not 'noCommdate' in page: #noCommdata是无评论json编码页面的关键字
        data=json.loads(page)['data'] #<strong>最关键的一部</strong>,json代码的解析并有效部分

        #通过正则匹配出相关信息,其中url是可能存在的,将稍后处理
        author=comment_author_pattern.findall(data)
        url=[]
        time=comment_time_pattern.findall(data)
        content=comment_content_pattern.findall(data)

        #后处理url,判断前面提取出来的author周边是不是带有<a>标签(超链接)即可
        for i in range(len(author)):
            comment_id+=1
            result=comment_url_pattern.search(author[i])
            if result:
                url.append(result.group(1))
                author[i]=result.group(2)
            else: url.append('')

        num+=1 #评论页数+1
        url=r'http://blog.sina.com.cn/s/comment_'+key+'_'+str(num)+'.html' #生成新的页面地址
        page=urllib2.urlopen(url).read().replace('data:','\"data\":',1) #修正data的双引号,重复循环

【后记】感谢 @lqs 学长和 北航开源俱乐部BHOSC的同胞们 在此问题上给予的帮助

精简WordPress eXtended Rss (WXR) 文件格式

经过N次Import和数据库清空,终于将之前的WXR文件格式的完备集简化了。

简化原则是适应Sina2WordPress项目的需要,尽可能精简文件大小,删除了导入无效的(如博客标题、博客链接等)和从新浪博客中无法获取的(如评论者的链接和IP等)信息,还有item之前的的作者、分类和标签信息。作者在导入时可以指定的,反而加上会有可能的错误,分类和标签的信息用post中的分类和标签就可以自动统计了。没想明白为什么非要单独列出来,难道是为了空的分类和标签,那还要它干嘛?

一些必不可少的标签及错误总结:
1、wxr_version,缺少会提示“missing/invalid WXR version number”的错误
2、post_id,否则只会导入第一篇文章
3、status,否则都会显示成draft
4、post_type,否则无法导入
5、comment_approved,否则无法导入

P.S.post_id的问题纠结了好久,为什么官方不好好设计一下呢?至少觉得应该在Settings设定对应的选项的……

< ?xml version="1.0" encoding="UTF-8" ?>

<rss version="2.0"
	xmlns:excerpt="http://wordpress.org/export/1.1/excerpt/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:wp="http://wordpress.org/export/1.1/"
>
<!--RSS版本号和名字空间的扩展,以上为固定内容-->

<channel>
	<wp:wxr_version>1.1</wp:wxr_version>
	<!--WXR格式版本号-->

	<item><!--页面或者日志内容,每个为一个item-->
		<title>Title test</title>
		<!--标题-->
		<content:encoded>< ![CDATA[Content_test]]></content:encoded>
		<!--这里是正文内容-->
		<wp:post_id>1</wp:post_id>
		<!--页面或日志的序号,两者使用同一序列-->
		<wp:post_date>2002-12-21 07:59:59</wp:post_date>
		<!--发表时间-->
		<wp:comment_status>open</wp:comment_status>
		<!--评论开启情况,open / closed-->
		<wp:status>publish</wp:status>
		<!--页面或日志状态,publish / draft / pending / private-->
		<wp:post_type>post</wp:post_type>
		<!--文章类型,post / page-->
		<wp:is_sticky>0</wp:is_sticky>
		<!--文章是否置顶,0 / 1-->

		<category domain="post_tag" nicename="tag_test">< ![CDATA[Tag Test]]></category>
		<category domain="category" nicename="category_test">< ![CDATA[Category Test]]></category>
		<!--
			日志或页面的标签和分类,可多个
			domain:标签对应post_tag,分类对应category
			nicename:对应标签或分类的URL友好名称
			<![CDATA[]]>:标签或分类的显示名称
		-->

		<wp:comment><!--评论,可多个-->
			<wp:comment_id>1</wp:comment_id>
			<!--自增序号,评论专用-->
			<wp:comment_author>< ![CDATA[anonymous]]></wp:comment_author>
			<!--评论者用户名-->
			<wp:comment_date>2012-12-21 07:59:59</wp:comment_date>
			<!--评论时间-->
			<wp:comment_content>< ![CDATA[Content of Comment]]></wp:comment_content>
			<!--评论内容-->
			<wp:comment_approved>1</wp:comment_approved>
			<!--评论是否被允许-->
			<wp:comment_parent>0</wp:comment_parent>
			<!--父评论,指定所回复的评论-->
		</wp:comment>
	</item>
</channel>
</rss>