前言
本次也是记录一个偶然发现的小问题,有关js逆向和app逆向的系列文章,放一放,有空再系统的整理成文发布了。
这个问题就很骚了,废话不多说,直接情景再现
目标网站:
aHR0cHM6Ly93d3cubW5kLmdvdi50dy9QdWJsaXNoTVBCb29rLmFzcHg/JnRpdGxlPSVFOCVCQiU4RCVFNCVCQSU4QiVFNSU4OCU4QSVFNyU4OSVBOSZTZWxlY3RTdHlsZT0lRTglQkIlOEQlRTQlQkElOEIlRTYlOUMlOUYlRTUlODglOEE=
复现问题
我们的目标就是要下载这个网站的资源文件
首先这个是一级页面,以下圈出的就是二级页面
进入二级页面,我下面圈出的地方就是三级页面地址
点击三级页面网址,三级页面其实就是在二级底部渲染出来的,下面圈出的什么什么下载的就是我们要的数据了
是不是看着很简单
好的,我们直接看他的请求接口:
前面两个都是get请求,第三个是post请求,所以我们着重点就在第三个,先看链接:
这里看下,有个值没有正常显示:
没事,这个不打紧了,再看请求体:
__EVENTTARGET: ctl00$ContentPlaceHolder1$RtList$ctl01$LkBt
__EVENTARGUMENT:
__VIEWSTATE: i2jc3XTd0XMvdzkJDXcki1wScYnJdfCuOoUlDvgf4ql6TMq8g84WYO1rZ6MyTNjqdoSpUkPNx8VG53Qo2d8+bDEpAlN5bx9At8ApkxRBaAVEthimHSC2wu1pZWg37peXtm+oMKecNXW3cFST4OEGp5rmb3IIcJ4iRnn6v2B6W5VGo3SsBIh5LOA4nAtX0ut87EN
__VIEWSTATEGENERATOR: 0361E37B
__EVENTVALIDATION: 7pEeFbpkgYsGh94FYMVpb/V2HHBATMf46U6yW9OlMx9O55RRM1pySTFubl19vw1ec9F9mBMNS+UZ46T/osr9+s+tOZv4G8ecnT2UsKcl7Vf0vill/V2uqzoLHOiqzkTQIkiUFlK1lwBv89wcIa0zUBdlUZ5/t+YSEEg2GYP7hOL7RpaJM6LOlwKIFrRQY/QiRQ3tL1KPBQ9vEIw3+SUxC905LH8wKjFiCsJpskpThyAR4aySYRF2yZbzNFHWMWiAgZQUd/9O3MXvK6/RZa42d9I8t7xJwAw==
TbSearch2:
TbSearch:
ctl00$ContentPlaceHolder1$txtSearch:
然后,看到这些值,搞过国内某某网站都懂,就是c#的web框架生成出来的值,然后这些值都是在网站源码里面能找到的,其他也不存在什么加密参数,所以,很简单啊,直接拿着代码一顿操作就完了
import requests
from lxml import etree
url = 'https://www.xxxxxxxxx/PublishMPBook.aspx?&title=xxxx%A9&SelectStyle=xxxxx6%xxxxA'
session = requests.session()
headers = {
'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
'sec-ch-ua-mobile': '?0',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
}
req = session.get(url, headers=headers)
res = req.content.decode('utf-8')
html = etree.HTML(res)
req.close()
data = html.xpath('//div[@class="thisPages"]/table/tr[position()>1]')
for item in data:
curr = dict()
link = item.xpath('./td[1]/a/@href')
link = ''.join(link) if link else ''
kind = item.xpath('./td[1]/a/@title')
kind = ''.join(kind) if kind else ''
pub_date = item.xpath('./td[@headers="LastUpdate"]/text()')
curr['pub_date'] = pub_date
pub_date = ''.join(pub_date) if pub_date else ''
name = item.xpath('./td[@headers="DepartmentName"]/text()')
name = ''.join(name) if name else ''
curr['name'] = name
link = 'https://www.mnd.gov.tw/' + link
sec_req = session.get(link, headers=headers)
sec_res = sec_req.content.decode('utf-8')
sec_req.close()
sec_html = etree.HTML(sec_res)
sec_data = sec_html.xpath('//table[@class="table-bordered"]/tr[position()>1]')
__VIEWSTATE = sec_html.xpath('//input[@>)
__VIEWSTATE = ''.join(__VIEWSTATE) if __VIEWSTATE else ''
__VIEWSTATEGENERATOR = sec_html.xpath('//input[@>)
__VIEWSTATEGENERATOR = ''.join(__VIEWSTATEGENERATOR) if __VIEWSTATEGENERATOR else ''
__EVENTVALIDATION = sec_html.xpath('//input[@>)
__EVENTVALIDATION = ''.join(__EVENTVALIDATION) if __EVENTVALIDATION else ''
# print(12312323,__EVENTVALIDATION,__VIEWSTATEGENERATOR,__VIEWSTATE)
# print(123132123,sec_data)
for sec_item in sec_data:
date = sec_item.xpath('./td[@headers="dates"]/text()')
date = ''.join(date) if date else ''
curr['date'] = date
__EVENTTARGET = sec_item.xpath('./td[@headers="MPTable"]/a/@href')
__EVENTTARGET = ''.join(__EVENTTARGET) if __EVENTTARGET else ''
__EVENTTARGET = __EVENTTARGET.replace("javascript:__doPostBack('", '').replace("','')", '')
thr_link = sec_item.xpath('//form[@name="aspnetForm"]/@action')
thr_link = ''.join(thr_link) if thr_link else ''
if thr_link:
thr_link = thr_link.replace('./', '')
thr_link = 'https://www.xxxxxxx/' + thr_link
formdata = {
'__EVENTTARGET': __EVENTTARGET,
'__EVENTARGUMENT': '',
'__VIEWSTATE': __VIEWSTATE,
'__VIEWSTATEGENERATOR': __VIEWSTATEGENERATOR,
'__EVENTVALIDATION': __EVENTVALIDATION,
'TbSearch2': '',
'TbSearch': '',
'ctl00$ContentPlaceHolder1$txtSearch': '',
}
new_headers = headers.copy()
new_headers.update({
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
})
thr_req = session.post(thr_link, headers=new_headers, data=formdata)
thr_res = thr_req.content.decode('utf-8')
thr_req.close()
thr_html = etree.HTML(thr_res)
thr_data = thr_html.xpath('//td[@>)
for thr_item in thr_data:
file_name = thr_item.xpath('./td[@headers="Subject"]/text()')
file_name = ''.join(file_name) if file_name else ''
curr['file_name'] = file_name
author = thr_item.xpath('./td[@headers="Publisher"]/text()')
author = ''.join(author) if author else ''
curr['author'] = author
file_link = thr_item.xpath('./td[@headers="Subject"]/input/@tile')
file_link = ''.join(file_link) if file_link else ''
curr['file_link'] = file_link
date_year_month = ' '
file_href = f'https://www.xxxxx/NewUpload/{date_year_month}/{file_link}'
curr['file_href'] = file_href
print(123123123213, curr) # 这里就是资源地址了,直接请求存储就行了
反正都不难,这对于很多朋友来说,这????are you kidding me?这么简单的东西值得你大费周章的解析?
嘿嘿嘿,我要不是遇到这个坑,我还真的觉得不至于
先不细说,调试运行看结果:
看着状态码是200,觉得稳得一批对吧,接着看xpath解析部分:
傻眼了吧,为什么会是空,按正常人逻辑,那多半是dom节点没取对是吧,好,看下返回的源码,一看就出问题了,网站平台的结果如下:
在结果里搜,问题大了,根本就没有啊
也就是,第三次请求本身就出问题了,根本没有返回正常结果,很奇怪了。
那我第一个想到的就是,估计那几个请求参数出问题了,排查了几个小时,就是没问题啊,我后面用postman单独测试最后一次请求:
就是有啊,我单独的把第三级的拿出来请求:
它就是没有正常的获取数据,很骚啊,而且不是一点半点的骚。
最后,我想到一个前端的概念,既然它是submit,看下源码有没有什么猫腻:
发现确实没有啊,url也就是它这里给的地址,也不存在什么csrf-token之类的,这是为啥啊,一时之间把我整不会了,貌似搞了几年的爬虫跟没搞过一样,这么个问题愣是没整出来,也不涉及js混淆,也不涉及接口加密,所有字段都摆在那,都能拿到,但是就是请求失败,这说实话多多少少有点伤自尊了
找到关键点
那如果真没有解决的话,我也就不会发这篇博客了,跟着分析了一波,既然是所谓的submit,好,那action其实不指定的话就是源地址,而源地址就是第二级链接的,我把第二级和第三级链接复制出来对比:
发现,也就title的值不一样,其他都是一样的,而刚才我特别做了截图,第三级的时候,url的params在浏览器里没有被正常解析:
突发奇想,我就用第二级的链接请求呢?有朋友估计有疑惑了,不对啊,你怎么能用第二级的链接作为第三级访问呢?你拿到这个网站分析了就知道了,从二级到三级的时候,其实网站上部分是没有任何变化,变化的是底部突然就多了资源下载列表:
回顾一下,二级页面:
三级页面:
如果您稍微懂一点前端知识的话就大概知道我在说什么了,不太理解的可以查下form表单标签的原理就懂了,好的,继续,这次直接用二级链接请求看看:
正常拿到结果,果然就是这个问题了
把最后的代码改成如下:
import requests from lxml import etree url = 'https://wxxxxxxStyle=xxxxx%E8%BB%8D%E4%BA%8B%E6%9C%9F%E5%88%8A' session = requests.session() headers = { 'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"', 'sec-ch-ua-mobile': '?0', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-User': '?1', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36', } req = session.get(url, headers=headers) res = req.content.decode('utf-8') html = etree.HTML(res) req.close() data = html.xpath('//div[@class="thisPages"]/table/tr[position()>1]') for item in data: curr = dict() link = item.xpath('./td[1]/a/@href') link = ''.join(link) if link else '' kind = item.xpath('./td[1]/a/@title') kind = ''.join(kind) if kind else '' pub_date = item.xpath('./td[@headers="LastUpdate"]/text()') curr['pub_date'] = pub_date pub_date = ''.join(pub_date) if pub_date else '' name = item.xpath('./td[@headers="DepartmentName"]/text()') name = ''.join(name) if name else '' curr['name'] = name link = 'https://wxxxxxxv.tw/' + link sec_req = session.get(link, headers=headers) sec_res = sec_req.content.decode('utf-8') sec_req.close() sec_html = etree.HTML(sec_res) sec_data = sec_html.xpath('//table[@class="table-bordered"]/tr[position()>1]') __VIEWSTATE = sec_html.xpath('//input[@>) __VIEWSTATE = ''.join(__VIEWSTATE) if __VIEWSTATE else '' __VIEWSTATEGENERATOR = sec_html.xpath('//input[@>) __VIEWSTATEGENERATOR = ''.join(__VIEWSTATEGENERATOR) if __VIEWSTATEGENERATOR else '' __EVENTVALIDATION = sec_html.xpath('//input[@>) __EVENTVALIDATION = ''.join(__EVENTVALIDATION) if __EVENTVALIDATION else '' # print(12312323,__EVENTVALIDATION,__VIEWSTATEGENERATOR,__VIEWSTATE) # print(123132123,sec_data) for sec_item in sec_data: date = sec_item.xpath('./td[@headers="dates"]/text()') date = ''.join(date) if date else '' curr['date'] = date __EVENTTARGET = sec_item.xpath('./td[@headers="MPTable"]/a/@href') __EVENTTARGET = ''.join(__EVENTTARGET) if __EVENTTARGET else '' __EVENTTARGET = __EVENTTARGET.replace("javascript:__doPostBack('", '').replace("','')", '') thr_link = sec_item.xpath('//form[@name="aspnetForm"]/@action') thr_link = ''.join(thr_link) if thr_link else '' if thr_link: thr_link = thr_link.replace('./', '') thr_link = 'https://wxxxxxw/' + thr_link formdata = { '__EVENTTARGET': __EVENTTARGET, '__EVENTARGUMENT': '', '__VIEWSTATE': __VIEWSTATE, '__VIEWSTATEGENERATOR': __VIEWSTATEGENERATOR, '__EVENTVALIDATION': __EVENTVALIDATION, 'TbSearch2': '', 'TbSearch': '', 'ctl00$ContentPlaceHolder1$txtSearch': '', } new_headers = headers.copy() new_headers.update({ 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' }) # thr_req = session.post(thr_link, headers=new_headers, data=formdata) thr_req = session.post(link, headers=new_headers, data=formdata) thr_res = thr_req.content.decode('utf-8') thr_req.close() thr_html = etree.HTML(thr_res) thr_data = thr_html.xpath('//td[@>) for thr_item in thr_data: file_name = thr_item.xpath('./td[@headers="Subject"]/text()') file_name = ''.join(file_name) if file_name else '' curr['file_name'] = file_name author = thr_item.xpath('./td[@headers="Publisher"]/text()') author = ''.join(author) if author else '' curr['author'] = author file_link = thr_item.xpath('./td[@headers="Subject"]/input/@tile') file_link = ''.join(file_link) if file_link else '' curr['file_link'] = file_link date_year_month = ' ' file_href = f'https://www.xxxxx/xxxx/{date_year_month}/{file_link}' curr['file_href'] = file_href print(123123123213, curr)
运行结果肯定是有的,就不费篇幅展示了
疑问
那细心的老哥估计要问了,为啥用postman和谷歌浏览器时,用的那个看到的三级链接就可以,在打码里得用二级链接才行?
卧槽,老哥,你问的这个问题,非常的专业,请看如下:
注意,上图右边的是python2环境下的,有没有发现,这可太对应了,也就【\】被替换成了【%】,那果然是这个编码的问题了,右边不难看出,就是unicode编码,而谷歌浏览器能解析的默认是url编码的,所以显示的unable decode,
而为啥python里不行,我想应该是python你给什么url它就是什么,而postman和谷歌会把url做一定编码处理吧,但是具体我没有去仔细研究了,反正就是这个问题了,over
对了,补一个python3里的unicode编码:
结语
所以啊,浏览器的抓包还是不能绝对相信啊,这可是个大坑啊,搞了几个小时搞出来的,心累。。。。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python爬虫 — 浏览器的抓包编码可以绝对信任吗 - Python技术站