按 ‘ Python ’ 标签归档

删除僵尸粉的自动化

在删除僵尸粉的自动化方面,做了一点微小的工作,免费分享一下。

准备过程有点复杂,既然是免费分享,服务支持是谈不上了,我只介绍大体如何设置,能看懂的应该就克服各种困难了,看不明白的也不能多解释了……

  1. 点这里,找Windows位数匹配的executable installer,获得Python编程语言,并一切按默认设置安装。
  2. 右击桌面左下角Windows图标,选“运行”,输入pip install selenium安装Selenium,这是用来遥控Chrome浏览器的Python模块。
  3. 点这里获得Chrome浏览器并一切按默认设置安装。
  4. 点这里获得Chrome Driver,或者,假如你已经有Chrome,可以到这里下载一个版本匹配的Chrome Driver,把解压后的.exe文件放到一个可执行路径目录里,如:C:\Windows。
  5. 点这里下载僵尸清除程序,解压后存到任何地方都可以(比如桌面)。右击解压后的spamfancleanse.py文件,Edit with IDLE,把下图所示的程序开头三行代码改成你真正的登录信息和用户信息(放心,不会偷你的登录信息),Ctrl-S存盘,按F5运行。

其它信息:

  1. 删除粉丝是一个无法回退的操作,请谨慎使用,作者对使用此免费程序带来的任何后果不承担责任。
  2. 这个程序并非黑进了渣浪的后台数据库,所有的浏览和删除都和正常的手动操作无异,看到的数据也并无不同。它只是接管了一系列枯燥的翻页和点按鼠标的动作,不叫苦不嫌累而已。
  3. 程序运行时,Chrome受控换页翻屏、菜单弹出收起的各种动作很好看,但不要多看,谨防沉迷。
  4. 所谓“病来如山倒,病去如抽丝”,删除僵尸粉的过程是很“稳健”的,最快两秒一个,没办法更快了,否则会被渣浪服务器拒绝访问。
  5. 随时可以关闭Chrome浏览器窗口终止这个程序,关闭时,监控小窗里会出现可忽略的错误信息。程序会随时把执行进度存到本地同目录的一个数据库里面,下次运行时会记得处理过谁,没处理过谁。数据库文件是本地同目录的spamfans,由程序第一次运行时产生。
  6. 第一次运行时它会根据上面三行代码登录,以后再运行时,它就记得登录状态了(根据存在本地同目录的weibo-cookies.txt文件,由程序产生),如果它偶尔忘记,还会根据代码里的信息再填。
  7. 程序运行时,尽量不要把鼠标在Chrome窗口上指来指去,不要把Chrome窗口最小化(用其它窗口遮蔽没事),以免干扰到它。业务十分繁忙的大V最好关闭转发和评论的小黄签提醒,它们可能会让页面元素失效,并使程序异常退出(如其发生,重新运行即可)。
  8. 如果程序跑了一段时间后,想转移到另一台机器上运行,除了设置说明里提到的那些步骤外,还要把spamfans文件一道拷过去,和spamfancleanse.py放到同一目录下。weibo-cookies.txt文件可拷可不拷。
  9. 不建议在多台机器上同时跑这个程序,虽然不会造成误删,也确实能提高效率,但多台机器对粉丝的密集访问可能会被渣浪留意到。
  10. 对“僵尸”的初步定义是粉丝少于5,发帖少于10,或者跟此人ID体现的注册年代不般配的(很早的ID,却粉丝及发帖甚少,没有传播力)。程序还会对初筛过的ID一个个翻看主页,最近3个月没说过话的会被移除(原创或转发都算“说话”,而系统产生的生日祝福、会员升级或者抢红包都不算)。躲过一次巡视的并非永久安全了,下次巡视发生在7天之后。
  11. 有时会在监控窗口里观察到程序针对某个ID反复输出UNSURE,这种问题通常是因为这个用户资料发博甚多,主页却空空如也(渣浪登记的微博数常常大于用户实际的发博数,要不说它渣呢),但程序不确定是服务器原因还是别的什么,所以不敢轻易下手删除。对于这样的用户,另开个浏览器手动删除即可,程序再来观察时会发现已被删除,就不再理它了。
  12. 12月9日,对“僵尸”的定义取消了对粉丝数的考量,因为这个是即使很有趣的博主也无法掌控的事。取消这个指标,也可以避免我自己的小号被删。
  13. 12月16日,在程序里加了个改进:当逐页扫描撞上沙里淘金浓缩而成的活粉大军时,它会跳过这段漫长的扫描,这样可以节约很多时间。另外,在反复筛查时,又会有较低随机概率扫描活粉大军,确保没有僵尸混进来。
  14. 12月18日发现,渣浪偶然会误报用户数据,把活跃用户的关注、粉丝、发博数报得极低(最甚者以上三个数都是零),造成“这是僵尸粉”的误判。对此偶发问题的应对方法是:当重逢某ID,发现微博所报其发博数急降时,则判为误报,不予理会。对于首次见到的ID,若有此问题,则无法解决。好在这种问题发作频度极低,写好应对代码之后,24小时尚未重现。

程序员入伙书——换还是不换

话说,这道题,十几年前,玩论坛的时代,就出现在网上了:

三道门,一道门后面有车,另外两道门,后面都是羊。
有个节目主持人,他知道车在那道门后。
他请你选一道门,但不立即打开。
他在剩下的两道门里,打开一道,放出一只羊给你看。
现在台上还剩两道门关着,一道是你选的,一道是谁也没碰过的。
主持人说:现在你有个机会,可以改变主意,挑另一道门。
不管你换还是不换,你最终选中的那道门,后头的东西都归你。
你换不换?——假设价值观是车比羊好。

当时,论坛上吵成一片,有说该换的,有说不该换的。对于不换而中奖的概率,大家比较一致:1/3。而对于换而中奖的概率,基本上有三个说法:1/3、1/2、2/3。

论坛上贴题的那人说:“正确答案是应该换,中奖概率会从1/3提升到2/3。并且,此答案经过了智商排名极靠前的一位人士的认可。不过,还是有许多不愿盲信权威的年轻人,自己动手,用各种办法做实验,有大活人亲自做的,有用计算机模拟的,而结果一致确认:该换,中奖概率确实提升到了2/3。另外,虽然实验结果如此,有相当多的亲手做实验的人依然坚持(理论上)不该换。”

时至今日,这道题提到人口稠密的社交媒体上来,依然能够引起争论。

为了让读者老爷们怀着轻松的心情观看余下的内容,我提前把答案确认一下:

应该换。
我不是从一道门换到另一道门,
而是从一道门换到另外两道门。
“换并且选到车”的概率 = “第一次没选到车”的概率

三道门的迷惑性较大,读者可以极端化一下:如果是一亿道门,你挑一扇(选中车的概率很悲观),然后主持人把许许多多门打开,放出来满坑满谷的羊,最后只留下一道门,你换不换?

或者再换一个思路:主持人挑你和另外一个现场观众上来,让你选一道门,让那位观众选两道门,然后问你,愿不愿意拿你的一道门换那位观众的两道门?

“开门放羊”只是个迷惑动作,当门的总数大于2时,挑剩下的门里,一定能放出至少一只羊。所以它没有增加任何信息,也没有改变概率分布,这一步骤和事后开奖并无不同。

用概率论的运算过程则是:

  • 换而中车的概率 =
            首次选羊的概率 × 拿羊换到车的概率 +
            首次选车的概率 × 拿车换到车的概率
  • 首次选羊的概率 = 2/3
  • 首次选车的概率 = 1/3
  • 拿羊换到车的概率 = 100%
  • 拿车换到车的概率 = 0%
  • 因此,换而中车的概率 = 2/3

如果你看到这里还是觉得数学上不该换,那就可以关掉页面了。接下来并没有理论上的新内容,而且因为要用程序表达,技术上会比较烧脑。我不想让你同时背两个包袱走路,会芯片过热的。

 
虽然这道题没有数学理论难度,我还是想拿它做个编程的例子。原因是,我发现用计算机的思维,可以洞穿这道题的本质。做完实验依然坚持不该换的人里面,一定没有用计算机模拟的。

我的第一版程序很简单(手机读者可用手指左右拖动代码区):

import random

def lottery(n, change):  # n是门的个数,change设置“换还是不换”
    car = random.randint(0, n - 1)   # 为车生成一个随机的门号
    pick = random.randint(0, n - 1)  # 我选择一个随机的门号
    # 如果我未选中车但愿意换,或者我选中了车并且不换
    if (pick != car and change) or (pick == car and not change):
        return True      # 我都会中奖
    else:                # 否则
        return False     # 就不会

repeat = 100      # 重复做此实验100次
win = 0           # “中奖”计数器置零
for i in range(repeat):
    if lottery(3, True):  # 每次都选择“换”
        win += 1          # 如果中奖,计数器加一
# 打印中奖百分比
print("%.2f%%" % (win / repeat * 100))

结果如何呢?运行三遍:

=============== RESTART: cargoat.py ===============
68.00%
>>> 
=============== RESTART: cargoat.py ===============
71.00%
>>> 
=============== RESTART: cargoat.py ===============
68.00%
>>> 

100次实验,如果选择“换”,中奖次数确实在2/3左右。当然我们也得反过来做一下,把lottery函数的第二个参数设为False:

repeat = 100      # 重复做此实验100次
win = 0           # “中奖”计数器置零
for i in range(repeat):
    if lottery(3, False):  # 每次都选择“不换”
        win += 1           # 如果中奖,计数器加一
# 打印中奖百分比
print("%.2f%%" % (win / repeat * 100))

运行三遍,选择“不换”的中奖概率确实较低:

=============== RESTART: cargoat.py ===============
34.00%
>>> 
=============== RESTART: cargoat.py ===============
34.00%
>>> 
=============== RESTART: cargoat.py ===============
27.00%
>>> 

还可以发现,实验的重复次数(repeat的值)越高,中奖概率越是稳定在2/3上,下面是repeat = 100000的三遍运行结果:

=============== RESTART: cargoat.py ===============
66.55%
>>> 
=============== RESTART: cargoat.py ===============
66.81%
>>> 
=============== RESTART: cargoat.py ===============
66.70%
>>> 

在这个程序里,原本热热闹闹的挑门、开门放羊、问你换不换的那些动作,一下子被简化成了“你第一次猜中的概率有多大”的问题。我刚才说:“做完实验依然坚持不该换的人里面,一定没有用计算机模拟的。”是因为写程序前,我先假装认为不该换,而写下lottery函数的前两行时,就找到了事情本质的描述方式(上面的粗大字体)。

 
然而,读者可能认为,我并没有精确地按照剧本来写,所以运算结果不可信。为此,我必须按照剧本写一遍程序,像宋小宝吃面那样,辣根和蒜瓣这些步骤都不能省。说实在的,因为需要彻底改变思路,写新程序很累,但我还是勉力完成了:
猛击阅读全文