接第三關,來到第四關,地址:http://www.heibanke.com/lesson/crawler_ex03/,長得和前兩關差不多,多了一行字:“密碼很長, 試是試不出來的, 需要找出來的哦”,暗示我們不可以通過循環(huán)來猜解,F(xiàn)12看了下源代碼,和前兩關長一樣,沒什么頭緒,隨便填了個賬號密碼,提示錯誤,但是也提示一個新鏈接可以找到密碼,點擊進去,頁面長這樣:

這哪是慢半拍啊,這是慢了N拍。。
看頁面信息,左邊是密碼位置,右邊是密碼的值,顧名思義,這應該是一串超長的密碼,根據位置打亂了順序,我們要做的就是把他按照位置順序拼起來(顧名思義個屁,我花了半小時才看懂是這個套路)。點擊第二頁地址變成這樣: http://www.heibanke.com/lesson/crawler_ex03/pw_list/?page=2,現(xiàn)在就很明顯了,總共13頁,循環(huán)請求到數(shù)據然后根據位置排序就可以得到密碼了。核心代碼:
for i in list(range(1, 14)):
result = get_page(url + str(i), data)
soup = BeautifulSoup(result, "html.parser")
trs = soup.find_all('tr')
for tr in trs:
position = tr.find_all('td')[0].text
pwd = tr.find_all('td')[1].text
if is_number(pwd):
passwordList[int(position)] = int(pwd)
print('密碼長度:%d' % len(passwordList))
# 按照dict的key排序
print('完整密碼',passwordList)
print('長度',len(passwordList))
passwordSortedList = sorted(passwordList.keys())
print('key排序后',passwordSortedList)
# 組合密碼
passwordResult = ''
for key in passwordSortedList:
passwordResult += str(passwordList[key])
print('組合密碼后結果', passwordResult)
得到密碼:4611369344132640696702831525331901157436394969113095791722511569,去http://www.heibanke.com/lesson/crawler_ex03/登錄,報錯。。。。
檢查代碼,沒發(fā)現(xiàn)什么問題,繼續(xù)測試,發(fā)現(xiàn)密碼變了,而且密碼位數(shù)也變了,有時候是64位,有時候是65位,再仔細檢查密碼列表頁面,注意到左側的密碼位置是隨機的,跳到最后一頁( http://www.heibanke.com/lesson/crawler_ex03/pw_list/?page=13)發(fā)現(xiàn)密碼列表只有4條(其他頁面有8條),所以密碼總共條數(shù)有8*12+4=100,但是我們得到的結果只有大概65位左右,說明這100條數(shù)據里面有重復的,再根據密碼位置是隨機的這一條件猜測,是不是我們應該重復請求這13頁數(shù)據直到湊夠100位密碼呢(這個猜測過程花了我一個多小時,打幾個字才幾分鐘而已)?來試試,修改代碼如下:
from urllib import request
from urllib import parse
from bs4 import BeautifulSoup
def get_page(url, params):
print('get url %s' % url)
data = parse.urlencode(params).encode('utf-8')
header = {
'User-Agent': r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
r'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3',
'Connection': 'keep-alive',
'Cookie':r'Hm_lvt_74e694103cf02b31b28db0a346da0b6b=1514366315; csrftoken=1yFgXVZtw2rACmTYDGABYKs9VWLWqbeH; sessionid=m4paft1uuvhm3thrwvdgwut2rvu8uz8d; Hm_lpvt_74e694103cf02b31b28db0a346da0b6b=1514428404',
'Refer':'http://www.heibanke.com/lesson/crawler_ex02/'
}
req = request.Request(url, data, headers=header)
page = request.urlopen(req).read()
page = page.decode('utf-8')
return page
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
count = 0
url = "http://www.heibanke.com/lesson/crawler_ex03/pw_list/?page="
token = '1yFgXVZtw2rACmTYDGABYKs9VWLWqbeH'
username = 'pkxutao'
# 構造post參數(shù)
data = {
'csrfmiddlewaretoken': token,
'username': 'pkxutao',
'password': -1
}
passwordList = {}
while len(passwordList) < 100:
for i in list(range(1, 14)):
result = get_page(url + str(i), data)
soup = BeautifulSoup(result, "html.parser")
trs = soup.find_all('tr')
for tr in trs:
position = tr.find_all('td')[0].text
pwd = tr.find_all('td')[1].text
if is_number(pwd):
passwordList[int(position)] = int(pwd)
if len(passwordList) == 100:
break
if len(passwordList) == 100:
break
print('密碼長度:%d' % len(passwordList))
if len(passwordList) < 100:
print('不夠100,繼續(xù)循環(huán)')
# 按照dict的key排序
print('完整密碼',passwordList)
print('長度',len(passwordList))
passwordSortedList = sorted(passwordList.keys())
print('key排序后',passwordSortedList)
# 組合密碼
passwordResult = ''
for key in passwordSortedList:
passwordResult += str(passwordList[key])
print('組合密碼后結果', passwordResult)
最后得到組合密碼:4877661813696344916326470648993670283105253381901613579433963964296911309656791722213725864815153639,去頁面上試試,bingo!
總結
這一關卡在了兩個地方,第一個地方就是沒意識到密碼列表里面左邊一列“密碼位置”的意思,這里不應該卡的,然而我花了半小時才懂這個套路,第二個就是卡在了密碼位數(shù),得到65位的密碼后其實應該能想到再去循環(huán)直到獲取到100位密碼的,但當時沒往這個方向想,第一想到的可能是不是作者在后臺生成了一套密碼規(guī)則,每個用戶不同時間得到的密碼都是不一樣的,當時只要滿足這個規(guī)則就能過關,但是這樣就解釋不通怎么去匹配時間,畢竟我返回到輸入密碼的地方后就和之前獲取到的密碼列表沒任何關系了(除非后臺有記住當前用戶訪問的密碼列表,但沒必要做這么復雜),最后才想到要循環(huán)獲取直到湊過100位,還是經驗問題,套路中的多,經驗也就上來了吧