這次給大家帶來複雜點的ajax請求該如何破?

sergiojune發表於2018-07-10

公眾號由於私人原因差不多一個月沒有更新了,首先還是得感謝沒有你們,沒有取關我,很開心。其次我會在以下的兩個月時間為大家輸出高質量的文章,讓你們能學到東西的同時,也可以讓我自己得到提升。好了,閒話不多說,開始正文!

本次文章是寫如何應對複雜點的ajax請求,上篇文章簡單寫了下簡單點的ajax請求,也就10行程式碼就可以把資料都抓下來了,可以說非常強大。有興趣的可以看看談談如何抓取ajax動態網站

本次需要用到的工具是charles工具進行抓包。這個工具大家自行百度下載,不會用的話也可以百度下,本篇文章就不對這個工具多說了。用這個工具是它有強大的搜尋功能,可以一鍵搜尋出我想要的網路請求。

這次網站是這個http://drugs.dxy.cn/

這次給大家帶來複雜點的ajax請求該如何破?

需求是獲取所有藥品的詳細資訊,第一眼看上去是覺得不難的,點了進去你才知道是有坑的。

這次給大家帶來複雜點的ajax請求該如何破?

比如上面這個,需要獲取詳細資訊就需要模擬點選那個三角形按鈕,就需要通過傳送ajax請求來進行獲取了。

這次給大家帶來複雜點的ajax請求該如何破?

而且在你點開的時候還需要進行登陸才可以獲取全部資訊,所以這就多了一步,我們需要先模擬登陸成功後才可以進行aax請求來獲取資訊,要不然沒用。

1.模擬登陸

登陸是在這個網址上進行登陸https://auth.dxy.cn/accounts/login?service=http%3A%2F%2Fdrugs.dxy.cn%2Flogin.do%3Fdone%3Dhttp%253A%252F%252Fdrugs.dxy.cn%252Fdrug%252F54565%252Fdetail.htm

這次給大家帶來複雜點的ajax請求該如何破?

可以看到需要驗證碼,不過問題不大,可以解決。這個時候我們需要開啟開發者工具,按下f12即可,然後點選持續日誌,進行登陸,可以看到下面的圖

這次給大家帶來複雜點的ajax請求該如何破?

拉下到fromdata可以看到下面資料

這次給大家帶來複雜點的ajax請求該如何破?

經過多次測試,username和password是登陸賬號和密碼,validatecode是驗證碼,nlt是一個加密引數,由js載入而來的,其他的都是不變的。由於nlt引數是由js載入的,這就需要用到charles工具了。

這次給大家帶來複雜點的ajax請求該如何破?

登陸成功之後很容易就可以在charles找到這個請求,讓我們先看看nlt引數是怎樣來的。

我們可以先複製這個nlt引數,然後在charles工具內按下ctrl+f就會出現這個頁面

這次給大家帶來複雜點的ajax請求該如何破?

把那兩個勾選上,然後把nlt引數內容填上,點選find就會看到下面的內容,下面就是產生nlt引數的地方,點選進去,可以看到下面內容。

這次給大家帶來複雜點的ajax請求該如何破?

nlt引數是在html裡面就提供的了,這就不需要去解析js了,這就相對容易點,再看看請求網址

這次給大家帶來複雜點的ajax請求該如何破?

請求網址可以看到是和登陸網址一樣的,說明nlt引數直接提供的了,我們只需要使用正則來將nlt引數提取出來即可,現在看看驗證碼是在哪個請求產生的就可以了。

這次給大家帶來複雜點的ajax請求該如何破?

這次給大家帶來複雜點的ajax請求該如何破?

看到上面這些就知道驗證碼怎樣來了,直接使用get請求對那個網址即可。

分析完了,接下來就是程式碼部分。

2.使用python來模擬登陸

def __get_nlt(self):
       """給ult引數"""
       url = "https://auth.dxy.cn/accounts/login?service=http%3A%2F%2Fdrugs.dxy.cn%2Flogin.do%3Fdone%3Dhttp%253A%252F%252Fdrugs.dxy.cn%252Fdrug%252F89790%252Fdetail.htm&qr=false&method=1"
       response = self.session.post(url)
       nlt = re.findall('nlt" value="([^"]+?)"', response.text)  # 匹配nlt引數
       return nlt

   def __login(self):
       """登陸網站"""
       # 登陸需要提交的表單
       print('進行登陸')
       data = {'username':  13060629578,  # 賬號
               'password':  'asd12678',  # 密碼
               'loginType''1',
               'validateCode':  self.__get_chapter(),  # 驗證碼
               'keepOnlineType''2',
               'trys':  '0',
               'nlt':  self.__get_nlt(),  # 獲取nlt引數
               '_eventId':  'submit'}
       # 登陸網址
       url = 'https://auth.dxy.cn/accounts/login?service=http%3A%2F%2Fdrugs.dxy.cn%2Flogin.do%3Fdone%3Dhttp%253A%252F%252Fdrugs.dxy.cn%252Fdrug%252F89790%252Fdetail.htm&qr=false&method=1'
       response = self.session.post(url, headers=self.headers, data=data)  # 請求登陸
       if 'dxy_zbadwxq6' in response.text:  # 此處填寫你的使用者名稱字,用於驗證是否登陸成功
           print('登陸成功')
       else:
           print('登陸失敗,正在嘗試重新登陸')
           self.__login()

   def __get_chapter(self):
       """獲取驗證碼"""
       try:
           url = 'https://auth.dxy.cn/jcaptcha'
           response = self.session.get(url, headers=self.headers)
           # 儲存驗證碼
           with open('code.jpg''wb')as f:
               f.write(response.content)
           im = Image.open('code.jpg')
           im.show()
           valide_code = input('輸入驗證碼')
           return valide_code
       except Exception as e:
           """驗證碼失敗,再次獲取"""
           print(e)
           self.__get_chapter()複製程式碼

這是部分重要程式碼,裡面都有註釋,就不多說了,進入重要部分吧。

3.分析ajax請求

登陸成功之後。隨便點進一個頁面都可以然後點選三角形按鈕都可以看到詳細內容

這次給大家帶來複雜點的ajax請求該如何破?

我們繼續使用charles工具來進行抓包,先對charles剛才抓的 包進行清理,然後點選頁面三角形按鈕來進學校獲取資訊

這次給大家帶來複雜點的ajax請求該如何破?

可以看到上面的這個請求 ,資料都是Unicode編碼的,我們需要轉,其實可以直接複製然後到命令列視窗進行列印即可,就可以看到這個就是我們想要的詳細資料

這次給大家帶來複雜點的ajax請求該如何破?

接著看下請求方式和其他需要的東西

這次給大家帶來複雜點的ajax請求該如何破?

這次給大家帶來複雜點的ajax請求該如何破?

可以看到,是個post請求,成功狀態碼是200,有很多引數,經過多次測試後,發現下面箭頭所指的五個引數都是會變化的,第一個為藥品id,第二個可以通過抓包發現(和上面獲取nlt引數都是一樣的方法)是經過js來載入的,注意,要想在charles裡面載入js要先把瀏覽器的快取先清除掉才行,要不然不會載入出來,抓包是抓不到的哈。第三個變的也是藥品的id,第四個就是通過藥品頁面載入出來的,而最後的batchId的起始id是2,之後每獲取一個詳細的內容該引數就加1。

這次給大家帶來複雜點的ajax請求該如何破?

這次給大家帶來複雜點的ajax請求該如何破?

好了,需要的內容都分析出來了,最後就是剩下實現部分了。

4.用程式碼來進行ajax請求

這個是獲取藥品的頁面內容的

def __get_content(self, item, href):
       """獲取需要提取的資訊"""
       param0 = int(re.findall('\d+', item)[0])
       href_id = re.findall('\d+', href)[0]
       html = self.__get_html(item)  # 獲取藥品的html資訊
       name = re.findall('fl commend">(.*?)<', html, re.S)[0].replace('\n''').replace('\t''')
       batchId = 2  # 初始化id,提交表單需要的,起始數字是2
       id = "20A548B2C7B5F05093DFD2C71F112EEE"  # scriptSessionId中的加密需要用到的資料
       scriptSessionId = id + str(int(random() * 1000))  # 獲取詳情頁需要的表單資料
       soup = BeautifulSoup(html, 'lxml')  # 使用bs4解析
       content_dd = soup.find_all('div', id='container')[0].find_all('dl')[0].find_all('dd', style=False)  # 獲取整個頁面的所有資料
       content_dt = soup.find_all('div', id='container')[0].find_all('dl')[0].find_all('dt')  # 獲取資料的型別,就是比如適應症
       keys = re.findall('<span.*?>(.*?):<', str(content_dt), re.S)  # 清洗資料
       values = []  # 儲存所有清洗後的資料
       for i in content_dd:  # 獲取所有的資料,並進行清洗
           if '...   ' in i.get_text():  # 這個證明資料不完整,需要進行點選
               param = re.search('id="([0-9]+?)_([\d]+?)"', str(i))
               # 獲取相關的表單資料
               param1 = param.group(2)
               # 獲取詳情內容
               data_content = detail = self.__get_detail(scriptSessionId, param0, param1, batchId)
               if 'img' in detail:  # 判斷是否有圖片連結
                   data_content = ''
                   for x in re.split('<img.*?/>', detail, re.S):
                       data_content += x
                   # 找圖片連結
                   src = re.findall("<img src='([^']+?)'", detail, re.S)
                   for s in src:
                       data_content += s+'  '
               data_content = self.dr.sub('', data_content).replace('\n'' ').replace('\t'' ')
               values.append(data_content)
               batchId += 1
           else:
               if '商品名稱' in i.get_text():
                   con = str(i)
               else:
                   con = self.dr.sub('', i.get_text().strip().replace('\n'' ').replace('\t'' '))
               values.append(con)複製程式碼

這個是獲取頁面中需要進行ajax的請求的方法


def __get_detail(self, scriptSessionId, param0, param1, batch_id):
       """獲取那些需要點選才能看到的所有資料,就是模擬點選"""
       data = {'callCount'1,
               'page''/drug/%s/detail.htm' % param0,  # 這個引數是藥品id
               'httpSessionId''',
               'scriptSessionId': scriptSessionId,  # 獲取對應的引數
               'c0-scriptName''DrugUtils',
               'c0-methodName''showDetail',
               'c0-id''0',
               'c0-param0''number:%s' % param0,  # 這個引數是藥品id
               'c0-param1''number:%s' % param1,  # 這個引數是需要獲取想想頁面的id
               'batchId': batch_id
               }
       # 請求頭
       headers = {
                   'User-Agent''Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36',
                   'content-type''text/plain'}
       # 傳送請求
       r = self.session.post('http://drugs.dxy.cn/dwr/call/plaincall/DrugUtils.showDetail.dwr', headers=headers, data=data)
       # 把返回的html編碼並找出相對應的資料
       detail = re.findall('"(.*?)"', r.text.encode('utf-8').decode("unicode-escape"), re.S)[0].strip()
       return detail複製程式碼

好了,就是這麼多了!上面重要的不是程式碼,而是思想,只要你的思路跟上了,別的什麼ajax請求都是這樣子的,所以爬蟲沒什麼難的,分析這些ajax請求主要還是怕遇到加密引數,需要解析那些混淆js,這些自然而然就是爬蟲的主要部分了,做爬蟲的主要還是想辦法避開這些東西。

最後

看到這裡的一般都是真愛粉了,首先還是得感謝你們得支援哈!!!如果覺得文章對你有用,不妨點個贊,留個言,轉個發哈。這就是對我最大的鼓勵。

推薦文章

利用python爬取網易雲音樂,並把資料存入mysql

談談如何抓取ajax動態網站


這次給大家帶來複雜點的ajax請求該如何破?

日常學python

程式碼不止bug,還有美和樂趣

相關文章