zoukankan      html  css  js  c++  java
  • 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内容

    我们实现了:

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

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

  • 相关阅读:
    PythonStudy——格式化输入小练习
    PythonStudy——运算符优先级 Operator precedence
    PythonStudy——逻辑运算符 Logical Operators
    ExtJS动态创建组件
    常见报表的JS代码
    sqlserver学习
    读写分离与锁分离
    oracle链接原理
    读java并发编程笔记
    日志机制在编程中的作用
  • 原文地址:https://www.cnblogs.com/numbbbbb/p/3428201.html
Copyright © 2011-2022 走看看