事情的原由,所有都來自於一個叫 邀請碼 的東西。。。。php
1024論壇的遊客成百上千萬,可是註冊從未開放註冊過,一直都是邀請碼註冊。會員機制很特殊,有連坐的懲罰,即下家若是被禁言了,上家也跟着倒黴。並且,自己註冊會員獲取邀請碼也很難,得養本身的號才行。這一切都致使了一個結果:真的是一碼難求啊。html
還有個特色,就是論壇發碼,通常都不發明碼,發的都是加了密的暗碼,好比下面這種:web
8d43#a8f182*1b53
正則表達式
上面這個暗碼, *
表明一個數字,0~9; #
表明一個字母,a~z;也有的就是用一個標點符號來表明一個數字或字母。一個暗碼可能被遮掩好多個字符。因此,若是不經過點很是手段,單靠人工一個一個的實驗,搶到邀請碼並註冊成功是很難的。小程序
那麼如何可以搶到碼呢?簡單來分析一下步驟,大體能夠分爲如下幾步:微信小程序
無心間,我在『皮克啪的鏟屎官交流羣』裏看到有一張這個圖:瀏覽器
可能大家看到這張圖,會是一臉懵逼的狀態。可是,若是結合我上面講述的那幾個步驟,大家就會發現,其實這個圖片裏面的信息,基本都涵蓋了。bash
只不過啊,這個註冊器是針對單個帖子而寫的。服務器
好比,論壇裏面經常有些帖子會在重大節日啥的,會在一個帖子裏面,每一個樓層跟着發碼,有的是明碼,有的是暗碼,大家看第一行,地址一欄的URL模式,就能看出來,這種URL表明的就是單獨帖子第幾頁的url。下面第二行的頁碼
,間隔
,和規則
則是可能表示最大頁數,訪問時間間隔(論壇刷新時間不得小於兩秒),以及十六位的邀請碼正則表達式。微信
接着探測進程,則是說檢測可能的邀請碼的post請求進程。
註冊信息啥的都不須要多說,以後的顯示結果啥的,這些都是錦上添花的東西而已。
因此,按照鏟屎官以前分析的思路,這個探測的過程是徹底可行的。那麼我注意到,論壇裏面最近有些帖子確實是在發碼,就好比,論壇裏面有個叫 蘇*
的用戶,就基本天天發個帖子,而後在帖子裏面,把邀請碼遮擋,作成暗碼,而後拆分紅三段,藏在帖子裏。並且這個用戶,基本天天上午發帖子。
針對這個需求,鏟屎官就利用早上吃早飯的時間,簡單的用Python寫了一個demo,過程基本實現了,中間的細節還須要填充,有些地方不是很完善,可是,骨架模型什麼的都已經搭建好了。
接下來就來講一下這段Python代碼中,再結合上面的思路,說一下他們的做用吧:
首先,咱們來在論壇裏面找到特定做者的帖子:
1 def requestFid7(self):
2 print("requestFid7")
3 fid7_url = self.root_url + "thread0806.php?fid=7"
4 fid7_header = {
5 "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",
6 "Accept-Encoding": "gzip, deflate",
7 "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",
8 }
9 request_result = requests.get(url=fid7_url,headers=fid7_header)
10 request_result.encoding = "gbk"
11 soup = BeautifulSoup(request_result.content, "html.parser")
12 tr_list = soup.find_all(name="tr", attrs={"class": "tr3 t_one tac"})
13 for tr_item in tr_list:
14 auth_temp = tr_item.find_all(name="a", attrs={"class": "bl"})
15 if len(auth_temp) != 0:
16 # print("auth: " + auth_temp[0].text)
17 if "蘇*" == auth_temp[0].text:
18 time_temp = tr_item.find_all(name="div", attrs={"class": "f12"})
19 if len(time_temp) != 0:
20 print("time: " + time_temp[0].text)
21 if "今天" in time_temp[0].text:
22 page_url = self.root_url + tr_item.find(name="a", attrs={"target": "_blank"})["href"]
23 print("找到了::: " + page_url)
24 self.parsePage(page_url)
25 break
26 print("requestfid7 finished")
複製代碼
這裏面,用 requests 來發送 GET 請求,爲了避免被屏蔽,咱們須要添加表頭數據。將返回的結果,咱們用 BeautifulSoup 來解析,當找到目標帖子,咱們就進入下一步,解析頁面,讀取帖子內容,抽離出來暗碼:
1 def parsePage(self, page_url):
2 page_header = {
3 "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",
4 "Accept-Encoding": "gzip, deflate",
5 "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",
6 }
7 request_result = requests.get(url=page_url, headers=page_header)
8 soup = BeautifulSoup(request_result.content, "html.parser")
9 print("parsePage")
10 body_temp = soup.find_all(name="div", attrs={"class": "tpc_content do_not_catch"})
11 if len(body_temp) != 0:
12 body_text = body_temp[0].text
13 code_one = re.compile("(1)[0-9a-f*]*").findall(body_text)[0]
14 code_two = re.compile("(2)[0-9a-f*]*").findall(body_text)[0]
15 code_three = re.compile("(3)[0-9a-f*]*").findall(body_text)[0]
16 mis_code = code_one[3:] + code_two[3:] + code_three[3:]
17 print("成功找到mis_code:" + mis_code)
18 self.generateCode(mis_code)
複製代碼
這裏沒什麼難度,主要就是經過 BeautifulSoup 來尋找到咱們要的文本文件,而後將文本文件中,提取出來咱們想要的暗碼,而後再拼起來。
可能有些同窗對這個文本文件不是很瞭解,我截取了一下,長這個樣子:
提取出來純文本文字以後,就是大概長這個樣子:
"我我的以爲是可以發揮很大效果的。(1)d*7ee因此作了按摩。生意好的時候一個月能賺個四五千,少的時候兩三千。(2)07e0ca我心想合着你也知道效果不大啊。(3)31b98這是我第一次在德國"
那麼咱們須要在這裏面匹配出來咱們想要的暗碼,這裏我就想到了萬能的正則表達式。可能有些同窗一聽正則表達式就頭大,不要緊,鏟屎官之前也頭大,可是自從看了這篇文章以後,再結合一些網上的正則表達式匹配網站,鏟屎官的正則表達式功力基本可以應付通常的請求了。
在線正則表達式驗證網站:tool.oschina.net/regex/
正則表達式文章:《讀懂正則表達式就這麼簡單》(https://www.cnblogs.com/zery/p/3438845.html)
這裏,咱們使用的正則表達式就是: [0-9a-f*]*
就能夠完美解決。咱們簡單來說一下這個正則表達式表達的含義。[0-9a-f*]
這部分用中括號包裹起來,表示每一位能夠匹配的字符,就是括號裏面的這些,數字和小寫字母,外加一個*
號,最後的那個*
號表示的則是以前中括號裏面包裹的東西,能夠重複屢次。若是想重複五次,則只須要將最後的*
號換成{5}
便可,大括號包裹表示重複的次數。
這樣,走到這一步,咱們就找到了咱們的暗碼,那麼接下來就就是計算邀請碼可能的狀況。
1# * 表明數字,@表明表明字母,#表明數字和字母
2 def generateCode(self, original_code):
3 print(original_code)
4 code_size = len(original_code)
5 cur_process = 1
6 while cur_process <= code_size:
7 cur_char = original_code[cur_process - 1: cur_process]
8 if cur_char == "*":
9 self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code, self.num_list)
10 elif cur_char == "@":
11 self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code, self.alpha_list)
12 elif cur_char == "#":
13 self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code, self.num_alpha_list)
14 else:
15 self.potential_code_list = self.replaceChar(self.potential_code_list, cur_process, original_code)
16 cur_process = cur_process + 1
17 print("length:" + str(len(self.potential_code_list)))
18 if len(self.potential_code_list) != 0:
19 for item in self.potential_code_list:
20 if self.checkCodeIsValid(item):
21 print("******** 這個邀請碼可使用: " + item + " *********")
22 self.flag = 1
23 break
複製代碼
這一部分我僅僅只是用*
來表數字,嚴格意義上講,這裏的生產過程並非很全面。每個可能的邀請碼狀況,咱們都會調用checkCodeIsValid()
方法來檢驗它是否可用:
1 def checkCodeIsValid(self, code):
2 print("check code: " + code)
3 # check_url = "register.php?#iframeload"
4 check_url_he = "https://dd.etet.men/register.php"
5 login_values = {
6 "reginvcode": code,
7 "action": "reginvcodeck"
8 }
9
10 login_header = {
11 "origin": self.root_url[:-1],
12 "content-type": "application/x-www-form-urlencoded",
13 "Referer": "https://dd.etet.men/register.php",
14 "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",
15 "Accept-Encoding": "gzip, deflate",
16 "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",
17 }
18
19 request_result = requests.post(check_url_he, data=login_values, headers=login_header)
20 result_text = request_result.text.split(">")
21 if len(result_text) > 1:
22 result = re.sub("\D", "", result_text[1])
23 print("check " + code + " : " + result)
24 if int(result) == 0:
25 return True
26 return False
複製代碼
這個東西的抓取過程,就是在註冊頁面,有個檢測邀請碼是否合法:
這裏,咱們經過查看源碼,就能夠發現當點擊這個按鈕的時候,你本地的電腦其實就是發送了一個Post請求來校驗邀請碼是否合法。
一旦校驗成功,則會打印到log裏。
最後就是拿着合法的邀請碼去完成註冊了,這一步也能夠用代碼寫好,鏟屎官這裏就不寫了。
大家會發現,其實上面的這些代碼,都只是發送一次請求所走的流程。實際狀況是咱們須要對論壇每隔一段時間就訪問一次,來檢測是否有發碼的帖子出來,因此,鏟屎官這裏用最簡單的方法來寫一個定時器:
1 def startTimer(self):
2 self.timer = threading.Timer(1, self.timeFunction)
3 self.timer.start()
4
5 def timeFunction(self):
6 if self.flag == 1:
7 print("即將打開瀏覽器:")
8 webbrowser.open_new("https://dd.etet.men/register.php")
9 webbrowser.get()
10 pass
11 print("第 " + str(self.count) + " 次請求:" + str(datetime.datetime.now()))
12 self.requestFid7()
13 self.count = self.count + 1
14 global timer
15 timer = threading.Timer(30, self.timeFunction)
16 timer.start()
複製代碼
好了,以上的代碼很少,代碼能夠修改的地方有不少,真的不少,具體的點,你能夠本身想。鏟屎官這個代碼運行了一下,惋惜那我的今天沒有發帖。
可是,交流羣裏有個小夥伴告訴我,這我的發的碼是假的,實際目的就是爲了給他的公衆號引流,kao,我說呢麼,這我的發的碼,檢查出來都是假的,並且新上岸的遊客也沒有報道。因此,鏟屎官以爲,這我的發的碼 95% 是假的。
不過,這波經歷不虧,雖然最後沒有搶到嗎,可是這種訓練的思路仍是有意義的。骨架已經搭建完成,後續能夠加入提早寫好的配置文件,將程序部署到服務器上面去運行,增長不一樣的header,代理,來防止被網站封掉等等。其實這個東西作出來,市場仍是蠻
大的,畢竟,好多遊客都沒有碼。
最後閒扯兩句,想要這個代碼的,請關注微信公衆號:『皮克啪的鏟屎官』,回覆『
同時,喜迎新春,鏟屎官本身編寫的
好了,最後,給你們帶來福利,新年送你們一個充電寶,新年須要電量滿滿的來過。抽獎條件:只須要關注微信公衆號:『皮克啪的鏟屎官』,掃描下面的圖片便可。超級簡單,2月1日開獎。