requests.post()
控制台抓包
打开方式几常用选项
1、打开浏览器,F12打开控制台,找到Network选项卡 2、控制台常用选项 1、Network: 抓取网络数据包 1、ALL: 抓取所有的网络数据包 2、XHR:抓取异步加载的网络数据包 3、JS : 抓取所有的JS文件 2、Sources: 格式化输出并打断点调试JavaScript代码,助于分析爬虫中一些参数 3、Console: 交互模式,可对JavaScript中的代码进行测试 3、抓取具体网络数据包后 1、单击左侧网络数据包地址,进入数据包详情,查看右侧 2、右侧: 1、Headers: 整个请求信息 General、Response Headers、Request Headers、Query String、Form Data 2、Preview: 对响应内容进行预览 3、Response:响应内容
response = requests.post(url,data=data,headers=headers) # data :post数据(Form表单数据-字典格式)
3.请求方式特点
GET请求 : 参数在URL地址中有显示
POST请求: Form表单提交数据
有道翻译破解案例(post)
1.目标
破解有道翻译接口,抓取翻译结果 # 结果展示 请输入要翻译的词语: elephant 翻译结果: 大象 ************************** 请输入要翻译的词语: 喵喵叫 翻译结果: mews
2.实现步骤
1、浏览器F12开启网络抓包,Network-All,页面翻译单词后找Form表单数据 2、在页面中多翻译几个单词,观察Form表单数据变化(有数据是加密字符串) 3、刷新有道翻译页面,抓取并分析JS代码(本地JS加密) 4、找到JS加密算法,用Python按同样方式加密生成加密数据 5、将Form表单数据处理为字典,通过requests.post()的data参数发送
具体实现
1.开启F2抓包,找到Form表但数据如下:
i: 喵喵叫 from: AUTO to: AUTO smartresult: dict client: fanyideskweb salt: 15614112641250 sign: 94008208919faa19bd531acde36aac5d ts: 1561411264125 bv: f4d62a2579ebb44874d7ef93ba47e822 doctype: json version: 2.1 keyfrom: fanyi.web action: FY_BY_REALTlME
2.在页面中多翻译几个单词,观察Form表单数据变化
salt: 15614112641250 sign: 94008208919faa19bd531acde36aac5d ts: 1561411264125 bv: f4d62a2579ebb44874d7ef93ba47e822 # 但是bv的值不变
3.一般为本地js文件加密,刷新页面,找到js文件并分析JS代码
# 方法1 Network - JS选项 - 搜索关键词salt # 方法2 控制台右上角 - Search - 搜索salt - 查看文件 - 格式化输出 # 最终找到相关JS文件 : fanyi.min.js
4.打开JS文件,分析加密算法,用Python实现
# ts : 经过分析为13位的时间戳,字符串类型 js代码实现: "" + (new Date).getTime() python实现: str(int(time.time()*1000)) # salt : ts + 0-9之间的随机数 js代码实现: ts+parseInt(10 * Math.random(), 10); python实现: ts + str(randow.randint(0-9)) # sign(设置断点调试,来查看 e 的值,发现 e 为要翻译的单词) js代码实现: n.md5("fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj") python实现: from hashlib import md5 string = "fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj" s = md5() s.update(string.encode()) sign = s.hexdigest() #bv 不变的值,不需要处理,直接复制
5.代码实现
import requests import time import random from hashlib import md5 class YdSpider(): def __init__(self): # url一定为为F12抓到的headers->General->Request self.url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' self.headers = { "Cookie": "OUTFOX_SEARCH_USER_ID=970246104@10.169.0.83; OUTFOX_SEARCH_USER_ID_NCOO=570559528.1224236; _ntes_nnid=96bc13a2f5ce64962adfd6a278467214,1551873108952; JSESSIONID=aaae9i7plXPlKaJH_gkYw; td_cookie=18446744072941336803; SESSION_FROM_COOKIE=unknown; ___rl__test__cookies=1565689460872", "Referer": "http://fanyi.youdao.com/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36", } # 获取salt,sign,ts def get_salt_sign_ts(self, word): # ts ts = str(int(time.time() * 1000)) # salt salt = ts + str(random.randint(0, 9)) # sign string = "fanyideskweb" + word + salt + "n%A-rKaT5fb[Gy?;N5@Tj" s = md5() s.update(string.encode()) sign = s.hexdigest() return salt, sign, ts # 主函数 def attack_yd(self, word): # 先拿到salt,sign,ts salt, sign, ts = self.get_salt_sign_ts(word) # 定义form表单数据为字典:data={} data = { 'i': word, 'from': 'AUTO', 'to': 'AUTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': salt, 'sign': sign, 'ts': ts, 'bv': 'cf156b581152bd0b259b90070b1120e6', 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_REALTlME' } # 直接发请求:request.post(url,data=data,headers=xxxx) res = requests.post( url=self.url, data=data, headers=self.headers ) # html = res.text html = res.json() print(html) result = html['translateResult'][0][0]['tgt'] # 获取相应请求 return result # 主函数 def main(self): # 输入翻译单词 word = input('请输入要翻译的单词') res = self.attack_yd(word) print("翻译结果",res) if __name__ == '__main__': s = YdSpider() s.main()
民政部网站数据抓取
1.目标
1、URL: http://www.mca.gov.cn/ - 民政数据 - 行政区划代码
即: http://www.mca.gov.cn/article/sj/xzqh/2019/
2、目标: 抓取最新中华人民共和国县以上行政区划代码
2.实现步骤
1.从民政数据网站中提取最新行政区划代码链接
# 特点 1、最新的在上面 2、命名格式: 2019年X月中华人民共和国县以上行政区划代码 # 代码实现 import requests from lxml import etree import re url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/' headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'} html = requests.get(url, headers=headers).text parse_html = etree.HTML(html) article_list = parse_html.xpath('//a[@class="artitlelist"]') for article in article_list: title = article.xpath('./@title')[0] # 正则匹配title中包含这个字符串的链接 if title.endswith('代码'): # 获取到第1个就停止即可,第1个永远是最新的链接 two_link = 'http://www.mca.gov.cn' + article.xpath('./@href')[0] print(two_link) break
2.从二级页面链接中提取真实链接(反爬-相应内容嵌入JS,指向新的链接)
1、向二级页面链接发请求得到响应内容,并查看嵌入的JS代码 2、正则提取真实的二级页面链接 # 相关思路代码 two_html = requests.get(two_link, headers=headers).text # 从二级页面的响应中提取真实的链接(此处为JS动态加载跳转的地址) new_two_link = re.findall(r'window.location.href="(.*?)"', two_html, re.S)[0]
3.在数据库中查询此条链接是否已经爬取,建立增量爬虫
1、数据库中建立version表,存储爬取的链接 2、每次执行程序和version表中记录核对,查看是否已经爬取过 # 思路代码 cursor.execute('select * from version') result = self.cursor.fetchall() if result: if result[-1][0] == two_link: print('已是最新') else: # 有更新,开始抓取 # 将链接再重新插入version表记录
4.代码实现
'''民政部网站数据抓取(增量爬虫)''' import requests from lxml import etree import re import pymysql class Govement(object): def __init__(self): self.one_url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/' self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'} self.db = pymysql.connect('192.168.153.138','tiger','123456','govdb') self.cursor = self.db.cursor() # 获取假链接 def get_flase_link(self): html = requests.get(self.one_url,headers=self.headers).text # 此处隐藏了真实的二级页面的url链接,通过js脚本生成,保存本地文件查看 parse_html = etree.HTML(html) a_list = parse_html.xpath('//a[@class="artitlelist"]') for a in a_list: title = a.get('title') # 正则匹配title中包含这个字符串的链接 if title.endswith('代码'): # 获取到第1个就停止即可,第1个永远是最新的链接 false_link = 'http://www.mca.gov.cn' + a.get('href') break # 提取真链接 self.get_real_link(false_link) def get_real_link(self,false_link): # 从已提取的two_link中提取二级页面的真实链接 two_html = requests.get(false_link, headers=self.headers).text # 从二级页面的响应中提取真实的链接(此处为JS动态加载跳转的地址) real_two_link = re.findall(r'window.location.href="(.*?)"', two_html, re.S)[0] self.incre_spider(real_two_link) def incre_spider(self,real_two_link): # 实现增量爬取 self.cursor.execute('select * from version') result = self.cursor.fetchall() if result: if result[0][0] == real_two_link: print('已是最新,无须爬取') else: self.get_data(real_two_link) self.cursor.execute('delete from version') self.cursor.execute('insert into version values(%s)',[real_two_link]) self.db.commit() # 用xpath直接提取数据 def get_data(self,real_two_link): real_two_html = requests.get(real_two_link,headers=self.headers).text parse_html = etree.HTML(real_two_html) # 基准xpath,提取每个信息的节点列表对象 tr_list = parse_html.xpath('//tr[@height=19]') city_info = {} for tr in tr_list: city_info['code'] = tr.xpath('./td[2]/text()')[0] city_info['name'] = tr.xpath('./td[3]/text()')[0] print(city_info) if __name__ == '__main__': spider = Govement() spider.get_flase_link()
import requests from lxml import etree import re import pymysql class GovmentSpider(): def __init__(self): self.url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/' self.headers={'User-Agent':'Mozilla/5.0'} self.db = pymysql.connect( '127.0.0.1','root','123456','govdb',charset='utf8' ) self.cursor = self.db.cursor() #获取假链接 def get_false_link(self): html = requests.get( url=self.url, headers = self.headers, ).text #等于content.decode() #解析 parse_html = etree.HTML(html) print(parse_html) #网页对象 a_list = parse_html.xpath('//a[@class="artitlelist"]') for a in a_list: #titel = a.xpath('./@titel')[0] #get()方法:获取某个属性的值 title = a.get('title') if title.endswith('代码'):#末尾以代码结束的 false_link = 'http://www.mca.gov.cn'+a.get('href') break # if false_link 在数据库表中没有: # self.get_true_link(false_link) # 把链接插入到数据库中 # else: # print('数据已经是最新,无需爬取') self.incr_spider(false_link) #增量爬取函数 def incr_spider(self, false_link): sel = 'select url from version ' self.cursor.execute(sel) # fetchall:(('http://xxx.html',),) result = self.cursor.fetchall() # not result:代表数据库version表中无数据 if not result: self.get_true_link(false_link) #可选操作:数据库version表中只保留最新一条数据 del_ = 'delete from version' self.cursor.execute(del_) # 把爬取后的url插入到version ins = 'insert into version values(%s)' self.cursor.execute(ins, [false_link]) self.db.commit() else: print('数据已经是最新,无需爬取') #获取真链接 def get_true_link(self,false_link): #先获取加链接的响应,然后根据响应获取真链接 html = requests.get( url=false_link, headers=self.headers ).text #利用正则提取真是链接 re_bds = r'window.location.href="(.*?)"' pattern = re.compile(re_bds,re.S) # 打印看看是否成功爬取头 # print(html) # with open('false_link.html','a') as f: # f.write(html) true_link = pattern.findall(html)[0] self.save_data(true_link) # print(true_link) #提取数据 def save_data(self,true_link): html = requests.get( url = true_link, headers = self.headers ).text #xpath提取数据 parse_html = etree.HTML(html) tr_list = parse_html.xpath('.//tr[@height="19"]') for tr in tr_list: code = tr.xpath('./td[2]/text()')[0].strip() name=tr.xpath('./td[3]/text()')[0].strip() print(name,code) def main(self): self.get_false_link() if __name__ == '__main__': spider=GovmentSpider() spider.main()