Python刷票小脚本——网络人气奖?不好意思,我要了

零、前言

最近参加微软的kinect大赛,报名之后发现有一个网络投票,票数最多的项目可以得到网络人气奖。

这种事,必然是要搞一搞!

说干就干。

说明:由于本人过于懒惰,所以就不截图了,让大家失望了!

重点看一下思想就可以了。

一、探查敌情

第一步先搞清楚投票的具体流程以及可能的限制条件。

经过研究之后,总结如下:

  • 投票需要登录
  • 注册帐号需要验证邮箱
  • 登录不需要验证码
  • 每个帐号一天可以投一次票,票数可以选择,从0~10
  • 投票不需要验证码

注意到红字了是吧,这就是最关键的地方了。

好了,我们的初步思路就出来了:

手动注册好帐号——代码模拟用户登录——登录之后进行投票

思路出来了,下面就是工具的选择。

二、工欲利其事。。。

语言嘛必然是我爱的Python。

工具的话,之前其实做过模拟登录,简单来说就是用一个模拟浏览器的Python插件,然后进行各种模拟用户操作,比如点击按钮啊输入信息啊之类的。

但是这类插件主要有两大问题:

  1. headless的很少
  2. 基本上对于HTML页面的操作只能应用于form

headless是什么呢,可以简单理解为后台操作。如果做不到headless,那么你运行的时候其实还是需要打开一个浏览器,只不过脚本会操作浏览器。

所以我们可以看到,做不到headless的话,不仅看起来非常低端(想象一下电脑屏幕上开着一个浏览器,然后自动输入东西,而你之只能傻坐着什么都不能做),并且使用起来很不方便,比如在没有图形界面的系统就无法使用了。

只能应用于form是什么意思呢,我们拿jQuery来对比吧。jQuery可以选择所有HTML里出现的东西,但是只能应用于form就意味着只能操作表单,对于其他元素就无能为力了。我不知道为什么会出现这种情况,可能是插件底层有一些限制吧,反正大部分插件都只能操作form。

给大家提供三个方案以供参考吧:

  • Ghost.py 支持headless并且可以操作所有元素,甚至可以运行js,你就知道这个有多强大了。唯一缺点——依赖PyQt或者PySide,你装一下这俩货就知道了,简直折磨死人。所以如果你不想折腾的话,还是不要用这个了。
  • splinter  半支持headless——splinter默认是不支持headless,但是可以在使用zope的一个插件的前提下headless,因为我用的是默认的,所以具体怎么做到headless没有研究,感兴趣的自己搞搞吧。不过估计八成不给力。。。splinter的功能同样很强大,可以操作所有元素。
  • mechanize  支持headless但是只能操作form

大概就是这样。

三、Just Do It

重复一下我们的思路:

登录——投票

因为我决定采用headless的方案,所以就使用mechanize。

登录的话没问题,登录框本来就是form。投票嘛。。。先放着!我们先把登录搞定。

直接上代码:

# coding:utf-8
import cookielib
import mechanize
import urllib

br = mechanize.Browser()
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
br.open('http://k4w.cn/user/index.html')
br.select_form(nr=0)
br.form['mail'] = 'xxxx@xxx.com'
br.form['password'] = 'xxxxxxx'
br.submit()

cookielib是用来操作cookie的。因为我们登录之后需要跳转到投票页面,如果我们不保留cookie,那么网站就会把我们当做未登录——别忘了,你现在是用代码在模拟登录,所以不要以为他会自动给你保存cookie。

代码很简单吧,我就不解释了,总之,打开页面——输入用户名密码——提交

可以输出一下结果看看:

.....同上.....
response = br.submit()
print response.read()

我们可以看到输出的HTML中有“xxx,欢迎你”这样的字样,说明已经成功登录了

下面就是重头戏了——如何投票。

先具体化投票的操作:

从下拉列表里选择“10”,然后点击确定。

我们已经知道,mechanize只能操作form,对于其他元素是无能为力的,所以我们不能直接来模拟人的操作。

那么该怎么办呢?

大家先思考5秒钟

。。。。。。。。

。。。。。

。。。

好吧我知道你直接翻下来了。

我当时可是思考了半天才想出来的啊!!!

我们可以换个思路,投票,表面上是人的操作,但是最终发送给服务器的其实是一个POST请求!所以,我们可以跳过模拟操作,直接发送请求!

好的,这下思路清晰了。我们先——等等,我们POST什么东西?

投票啊,告诉服务器我们投票了。

但是代码是一个很严谨的东西,格式不对的话服务器是不认的!

好吧,这次不思考了,直接告诉你答案吧。

我们先手动投一次票,然后查看POST请求中的数据格式。

我用的是firebug,打开firebug,然后选择票数,按确定按钮,可以看到firebug中出来了这次POST请求的具体信息。

我们点开信息,可以看到数据的格式:

z_data : 10
id : 99
sid : 78

一下就看出来了嘛!

z_data是票数,id是项目编号,sid。。。好吧我不知道这是什么。总之就写78好了。

数据格式获取到了,下面我们回到代码中,模拟一个POST请求:

parameters = {'z_data' : '10',
                  'id' : '99',
                  'sid' : '78'
                 }              #  POST data
data = urllib.urlencode(parameters)
response = br.open('http://k4w.cn/zone/z_num.html', data)

很简单吧?

别忘了import urllib!

好了,我们和前面的代码组合起来实验一下,看看效果。

发现票数确实增加了,我们的方法是可行的。

然后呢,我们改一下,加个for循环,这样就可以按照我们设定好的用户名密码,自动登录所有用户并投票。

基本功能就是这样了,但是使用了几天之后发现了一个不爽的地方:投票完要想查看票数还得手动打开网页。如果能直接显示出来当前票数就好了!

于是我们继续踏上征程。

四、迭代好吃吗

首先还是思路:

打开项目页面——获取票数——显示

打开页面我们已经会了,br.open()就行。显示也很简单,print。那么怎么获取票数呢?

给大家介绍一个新工具——BeautifulSoup,靓汤!

我承认名字有点。。。。

不管了,继续我们编程之路。

靓汤是一个解析HTML的插件,介绍完毕。

我们可以把获取到的HTML用靓汤解析一下,然后找到我们需要的票数对应的那个元素,就可以获取票数了。

很简单是吧!我们把HTML传入靓汤。。。。

我靠怎么出错了!

Google了半天,原来是HTML中有不规范的标签,就解析失败了。

微软的页面原来也不符合标准。。。

好吧,解析不了,怎么办呢?

有人给出了解决办法:用lxml。

lxml又是个什么东西?lxml是解析xml的一个插件,但是可以解析HTML并且,注意啊,并且可以忽略不规范的标签。

正好是我们需要的!

OK,照着官方文档使用一下~

亮代码:

br = mechanize.Browser()
response = br.open('http://k4w.cn/level_search/1/78/0/0/0.html')
page = etree.HTML(response.read().lower().decode('utf-8'))
hrefs = page.xpath(u"//span[@class='number n_99']")
print "当前票数:" + hrefs[0].text

依然是很简单不解释,看看就明白了。

好的,这样我们整个刷票脚本就完工了~~

所有代码来个合影

# coding:utf-8
import cookielib
import mechanize
import urllib
from lxml import etree

all_data = [['username1', 'password1'], ['username2', 'password2']]
for i in all_data:
    br = mechanize.Browser()
    cj = cookielib.LWPCookieJar()
    br.set_cookiejar(cj)
    br.open('http://k4w.cn/user/index.html')
    br.select_form(nr=0)
    br.form['mail'] = i[0]
    br.form['password'] = i[1]
    br.submit()
    response = br.open('http://k4w.cn/level_search/1/78/0/0/0.html')
    parameters = {'z_data' : '10',
                  'id' : '99',
                  'sid' : '78'
                 }              #  POST data
    data = urllib.urlencode(parameters)
    response = br.open('http://k4w.cn/zone/z_num.html', data)
    print "%s 投票成功!" % i[0]
br = mechanize.Browser()
response = br.open('http://k4w.cn/level_search/1/78/0/0/0.html')
page = etree.HTML(response.read().lower().decode('utf-8'))
hrefs = page.xpath(u"//span[@class='number n_99']")
print "当前票数:" + hrefs[0].text

搞定。

五、总结

我们使用了:

  • mechanize  模拟用户操作  模拟POST请求
  • firebug  获取POST数据格式
  • lxml  解析HTML内容

我们实现了:

  • 自动登录
  • 自动投票
  • 输出票数

好了,下面只要把这个脚本放到服务器上,并且设置一下每天运行就可以了。

原文地址:https://www.cnblogs.com/numbbbbb/p/3428201.html