事情的起因,全部都来自于一个叫 邀请码 的东西。。。。
1024论坛的游客成百上千万,但是注册从未开放注册过,一直都是邀请码注册。会员机制很特殊,有连坐的惩罚,即下家如果被禁言了,上家也跟着倒霉。而且,本身注册会员获取邀请码也很难,得养自己的号才行。这一切都导致了一个结果:真的是一码难求啊。
还有个特点,就是论坛发码,一般都不发明码,发的都是加了密的暗码,比如下面这种:
8d43#a8f182*1b53
上面这个暗码, *
代表一个数字,0~9; #
代表一个字母,a~z;也有的就是用一个标点符号来代表一个数字或字母。一个暗码可能被遮掩好多个字符。所以,如果不通过点非常手段,单靠人工一个一个的实验,抢到邀请码并注册成功是很难的。
那么如何能够抢到码呢?简单来分析一下步骤,大致可以分为以下几步:
- 从论坛里面扒取带有『福利』字样的帖子,但是这有个问题,就是无法准确的区分出来,哪些帖子有码,哪些帖子没有码。
- 从上一步扒出来的帖子里面,通过正则表达式匹配出来暗码。但这里又有个问题,一般帖子里面的遮挡符号,不一定是
*
仅代表数字,也许#
仅代表数字之类的。 - 然后通过匹配出来的暗码,计算出明码的可能性。
- 接着通过注册页面有一个检测邀请码是否可以使用的form,我们需要模拟出来一个post请求。
- 最后就是发送Post请求,完成注册流程就好。
无意间,我在『皮克啪的铲屎官交流群』里看到有一张这个图:
可能你们看到这张图,会是一脸懵逼的状态。但是,如果结合我上面讲述的那几个步骤,你们就会发现,其实这个图片里面的信息,基本都涵盖了。
只不过啊,这个注册器是针对单个帖子而写的。
比如,论坛里面常常有些帖子会在重大节日啥的,会在一个帖子里面,每个楼层跟着发码,有的是明码,有的是暗码,你们看第一行,地址一栏的URL模式,就能看出来,这种URL代表的就是单独帖子第几页的url。下面第二行的页码
,间隔
,和规则
则是可能表示最大页数,访问时间间隔(论坛刷新时间不得小于两秒),以及十六位的邀请码正则表达式。
接着探测进程,则是说检测可能的邀请码的post请求进程。
注册信息啥的都不需要多说,之后的显示结果啥的,这些都是锦上添花的东西而已。
所以,按照铲屎官之前分析的思路,这个探测的过程是完全可行的。那么我注意到,论坛里面最近有些帖子确实是在发码,就比如,论坛里面有个叫 苏*
的用户,就基本每天发个帖子,然后在帖子里面,把邀请码遮挡,做成暗码,然后拆分成三段,藏在帖子里。而且这个用户,基本每天上午发帖子。
针对这个需求,铲屎官就利用早上吃早饭的时间,简单的用Python写了一个demo,过程基本实现了,中间的细节还需要填充,有些地方不是很完善,但是,骨架模型什么的都已经搭建好了。
接下来就来说一下这段Python代码中,再结合上面的思路,说一下他们的作用吧:
首先,我们来在论坛里面找到特定作者的帖子:
def requestFid7(self):
print("requestFid7")
fid7_url = self.root_url + "thread0806.php?fid=7"
fid7_header = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2412.123 Safari/497.06",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,ru;q=0.5",
}
request_result = requests.get(url=fid7_url,headers=fid7_header)
request_result.encoding = "gbk"
soup = BeautifulSoup(request_result.content, "html.parser")
tr_list = soup.find_all(name="tr", attrs={"class": "tr3 t_one tac"})
for tr_item in tr_list:
auth_temp = tr_item.find_all(name="a", attrs={"class": "bl"})
if len(auth_temp) != 0:
# print("auth: " + auth_temp[0].text)
if "苏*" == auth_temp[0].text:
time_temp = tr_item.find_all(name="div", attrs={"class": "f12"})
if len(time_temp) != 0:
print("time: " + time_temp[0].text)
if "今天" in time_temp[0].text:
page_url = self.root_url + tr_item.find(name="a", attrs={"target": "_blank"})["href"]
print("找到了::: " + page_url)
self.parsePage(page_url)
break
print("requestfid7 finished")
这里面,用 requests 来发送 GET 请求,为了不被屏蔽,我们需要添加表头数据。将返回的结果,我们用 BeautifulSoup 来解析,当找到目标帖子,我们就进入下一步,解析页面,读取帖子内容,抽离出来暗码:
def parsePage(self, page_url):
page_header = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2412.123 Safari/497.06",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,ru;q=0.5",
}
request_result = requests.get(url=page_url, headers=page_header)
soup = BeautifulSoup(request_result.content, "html.parser")
print("parsePage")
body_temp = soup.find_all(name="div", attrs={"class": "tpc_content do_not_catch"})
if len(body_temp) != 0:
body_text = body_temp[0].text
code_one = re.compile("(1)[0-9a-f*]*").findall(body_text)[0]
code_two = re.compile("(2)[0-9a-f*]*").findall(body_text)[0]
code_three = re.compile("(3)[0-9a-f*]*").findall(body_text)[0]
mis_code = code_one[3:] + code_two[3:] + code_three[3:]
print("成功找到mis_code:" + mis_code)
self.generateCode(mis_code)
这里没什么难度,主要就是通过 BeautifulSoup 来寻找到我们要的文本文件,然后将文本文件中,提取出来我们想要的暗码,然后再拼起来。
可能有些同学对这个文本文件不是很了解,我截取了一下,长这个样子:
提取出来纯文本文字之后,就是大概长这个样子:
"我个人觉得是能够发挥很大效果的。(1)d7ee所以做了按摩。生意好的时候一个月能赚个四五千,少的时候两三千。(2)07e0ca我心想合着你也知道效果不大啊。(3)31b98这是我第一次在德国"*
那么我们需要在这里面匹配出来我们想要的暗码,这里我就想到了万能的正则表达式。可能有些同学一听正则表达式就头大,没关系,铲屎官以前也头大,但是自从看了这篇文章之后,再结合一些网上的正则表达式匹配网站,铲屎官的正则表达式功力基本能够应付一般的请求了。
在线正则表达式验证网站:http://tool.oschina.net/regex/
正则表达式文章:《读懂正则表达式就这么简单》(https://www.cnblogs.com/zery/p/3438845.html)
这里,我们使用的正则表达式就是: [0-9a-f*]*
就可以完美解决。我们简单来讲一下这个正则表达式表达的含义。[0-9a-f*]
这部分用中括号包裹起来,表示每一位可以匹配的字符,就是括号里面的这些,数字和小写字母,外加一个*
号,最后的那个*
号表示的则是之前中括号里面包裹的东西,可以重复多次。如果想重复五次,则只需要将最后的*
号换成{5}
即可,大括号包裹表示重复的次数。
这样,走到这一步,我们就找到了我们的暗码,那么接下来就就是计算邀请码可能的情况。
# * 代表数字,@代表代表字母,#代表数字和字母
def generateCode(self, original_code):
print(original_code)
code_size = len(original_code)
cur_process = 1
while cur_process <= code_size:
cur_char = original_code[cur_process - 1: cur_process]
if cur_char == "*":
self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code, self.num_list)
elif cur_char == "@":
self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code, self.alpha_list)
elif cur_char == "#":
self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code, self.num_alpha_list)
else:
self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code)
cur_process = cur_process + 1
print("length:" + str(len(self.potential_code_list)))
if len(self.potential_code_list) != 0:
for item in self.potential_code_list:
if self.checkCodeIsValid(item):
print("******** 这个邀请码可以使用: " + item + " *********")
self.flag = 1
break
这一部分我仅仅只是用*
来表数字,严格意义上讲,这里的生产过程并不是很全面。每一个可能的邀请码情况,我们都会调用checkCodeIsValid()
方法来检验它是否可用:
def checkCodeIsValid(self, code):
print("check code: " + code)
# check_url = "register.php?#iframeload"
check_url_he = "https://dd.etet.men/register.php"
login_values = {
"reginvcode": code,
"action": "reginvcodeck"
}
login_header = {
"origin": self.root_url[:-1],
"content-type": "application/x-www-form-urlencoded",
"Referer": "https://dd.etet.men/register.php",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2412.123 Safari/497.06",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6,ru;q=0.5",
}
request_result = requests.post(check_url_he, data=login_values, headers=login_header)
result_text = request_result.text.split(">")
if len(result_text) > 1:
result = re.sub("\D", "", result_text[1])
print("check " + code + " : " + result)
if int(result) == 0:
return True
return False
这个东西的抓取过程,就是在注册页面,有个检测邀请码是否合法:
这里,我们通过查看源码,就可以发现当点击这个按钮的时候,你本地的电脑其实就是发送了一个Post请求来校验邀请码是否合法。
一旦校验成功,则会打印到log里。
最后就是拿着合法的邀请码去完成注册了,这一步也可以用代码写好,铲屎官这里就不写了。
你们会发现,其实上面的这些代码,都只是发送一次请求所走的流程。实际情况是我们需要对论坛每隔一段时间就访问一次,来检测是否有发码的帖子出来,所以,铲屎官这里用最简单的方法来写一个定时器:
def startTimer(self):
self.timer = threading.Timer(1, self.timeFunction)
self.timer.start()
def timeFunction(self):
if self.flag == 1:
print("即将打开浏览器:")
webbrowser.open_new("https://dd.etet.men/register.php")
webbrowser.get()
pass
print("第 " + str(self.count) + " 次请求:" + str(datetime.datetime.now()))
self.requestFid7()
self.count = self.count + 1
global timer
timer = threading.Timer(30, self.timeFunction)
timer.start()
好了,以上的代码不多,代码可以修改的地方有很多,真的很多,具体的点,你可以自己想。铲屎官这个代码运行了一下,可惜那个人今天没有发帖。
但是,交流群里有个小伙伴告诉我,这个人发的码是假的,实际目的就是为了给他的公众号引流,kao,我说呢么,这个人发的码,检查出来都是假的,而且新上岸的游客也没有报道。所以,铲屎官觉得,这个人发的码 95% 是假的。
不过,这波经历不亏,虽然最后没有抢到吗,但是这种训练的思路还是有意义的。骨架已经搭建完成,后续可以加入提前写好的配置文件,将程序部署到服务器上面去运行,增加不同的header,代理,来防止被网站封掉等等。其实这个东西做出来,市场还是蛮
大的,毕竟,好多游客都没有码。
最后闲扯两句,想要这个代码的,请关注微信公众号:『皮克啪的铲屎官』,回复『代码』即可得到你想要的结果。
同时,喜迎新春,铲屎官自己编写的《六十四卦》微信小程序改版上线喽。新增好多新功能,同时还添加了卦象分享功能,你可以把自己的新年运势分享出来,发到朋友圈里,来年图个喜庆。下图则是铲屎官的新年运势。顺道说一句,卦象解析页面的小游戏,其实挺好玩的。
好了,最后,给大家带来福利,新年送大家一个充电宝,新年需要电量满满的来过。抽奖条件:只需要关注微信公众号:『皮克啪的铲屎官』,扫描下面的图片即可。超级简单,2月1日开奖。
这么硬核的公众号,为啥还不关注一波?

网友评论