这次给大家带来复杂点的ajax请求该如何破?

公众号由于私人原因差不多一个月没有更新了,首先还是得感谢没有你们,没有取关我,很开心。其次我会在以下的两个月时间为大家输出高质量的文章,让你们能学到东西的同时,也可以让我自己得到提升。好了,闲话不多说,开始正文!

本次文章是写如何应对复杂点的ajax请求,上篇文章简单写了下简单点的ajax请求,也就10行代码就可以把数据都抓下来了,可以说非常强大。有兴趣的可以看看谈谈如何抓取ajax动态网站

本次需要用到的工具是charles工具进行抓包。这个工具大家自行百度下载,不会用的话也可以百度下,本篇文章就不对这个工具多说了。用这个工具是它有强大的搜索功能,可以一键搜索出我想要的网络请求。

这次网站是这个http://drugs.dxy.cn/

需求是获取所有药品的详细信息,第一眼看上去是觉得不难的,点了进去你才知道是有坑的。

比如上面这个,需要获取详细信息就需要模拟点击那个三角形按钮,就需要通过发送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

可以看到需要验证码,不过问题不大,可以解决。这个时候我们需要打开开发者工具,按下f12即可,然后点击持续日志,进行登陆,可以看到下面的图

拉下到fromdata可以看到下面数据

经过多次测试,username和password是登陆账号和密码,validatecode是验证码,nlt是一个加密参数,由js加载而来的,其他的都是不变的。由于nlt参数是由js加载的,这就需要用到charles工具了。

登陆成功之后很容易就可以在charles找到这个请求,让我们先看看nlt参数是怎样来的。

我们可以先复制这个nlt参数,然后在charles工具内按下ctrl+f就会出现这个页面

把那两个勾选上,然后把nlt参数内容填上,点击find就会看到下面的内容,下面就是产生nlt参数的地方,点击进去,可以看到下面内容。

nlt参数是在html里面就提供的了,这就不需要去解析js了,这就相对容易点,再看看请求网址

请求网址可以看到是和登陆网址一样的,说明nlt参数直接提供的了,我们只需要使用正则来将nlt参数提取出来即可,现在看看验证码是在哪个请求产生的就可以了。

看到上面这些就知道验证码怎样来了,直接使用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请求

登陆成功之后。随便点进一个页面都可以然后点击三角形按钮都可以看到详细内容

我们继续使用charles工具来进行抓包,先对charles刚才抓的 包进行清理,然后点击页面三角形按钮来进学校获取信息

可以看到上面的这个请求 ,数据都是Unicode编码的,我们需要转,其实可以直接复制然后到命令行窗口进行打印即可,就可以看到这个就是我们想要的详细数据

接着看下请求方式和其他需要的东西

可以看到,是个post请求,成功状态码是200,有很多参数,经过多次测试后,发现下面箭头所指的五个参数都是会变化的,第一个为药品id,第二个可以通过抓包发现(和上面获取nlt参数都是一样的方法)是经过js来加载的,注意,要想在charles里面加载js要先把浏览器的缓存先清除掉才行,要不然不会加载出来,抓包是抓不到的哈。第三个变的也是药品的id,第四个就是通过药品页面加载出来的,而最后的batchId的起始id是2,之后每获取一个详细的内容该参数就加1。

好了,需要的内容都分析出来了,最后就是剩下实现部分了。

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动态网站


日常学python

代码不止bug,还有美和乐趣

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值