python爬虫笔记


序言

网络爬虫的价值其实就是数据的价值,在互联网社会中,数据是无价之宝,一切皆为数据,谁拥有了大量有用的数据,谁就拥有了决策的主动权。
爬虫主要涉及的几大领域

工商、短视频、电商、航空、自媒体、外卖


一、爬虫基本原理

1.1常见基本功

1.1 获取网页

爬虫首先要做的工作就是获取网页,这里就是获取网页的源代码。源代码里包含了网页的部分有用信息,所以只要把源代码获取下来,就可以从中提取想要的信息了。

1.2 提取信息

获取网页源代码后,接下来就是分析网页源代码,从中提取我们想要的数据。
另外,由于网页的结构有一定的规则,所以还有一些根据网页节点属性、css 选择器或 xPath 来提取网页信息的库,如 Beautiful soup、pyquery、lxml 等。
使用这些库,我们可以高效快速地从中提取网页信息,如节点的属性、文本值等。提取信息是爬虫非常重要的部分,它可以使杂乱的数据变得条理清晰,以便我们后续处理和分析数据。

1.3 保存数据

提取信息后,我们一般会将提取到的数据保存到某处以便后续使用。这里保存形式有多种多样,如可以简单保存为 TXT文本或 JSON 文本,也可以保存到数据库,如 MySQL 和 MongoDB 等,也可保存至远程服务器,如借助 SFTP 进行操作等。
在这里插入图片描述

1.2 请求

请求,由客户端向服务端发出,可以分为4部分内容:请求方法(Request Method)、请求的网址(Request URL)、请求头(Request Headers)、请求体(Request Body)。

1.2.1 请求方法

方法描述
GET请求页面,并返回页面内容
HEAD类似于 GET请求,只不过返回的响应中没有具体的内容,用于获取报头
POST大多用于提交表单或上传文件,数据包含在请求体中
PUT从客户端向服务器传送的数据取代指定文档中的内容
DELETE请求服务器删除指定的页面
CONNECT把服务器当作跳板,让服务器代替客户端访问其他网页
OPTIONS允许客户端查看服务器的性能
TRACE回显服务器收到的请求,主要用于测试或诊断

1.2.2 请求网址

请求的网址,即统一资源定位符 URL,它可以唯一确定我们想请求的资源。

https://www.baidu.com/s?wd=python
http:// zb.yfb.qianlima.com /yfbsemsite/mesinfo/zbpglist
http 协议
zb.yfb.qianlima.com–》IP地址
/yfbsemsite/mesinfo/zbpglist 查询路径
wd=python 查询字符串 査询参数 这个参数会传输给服务器 服务器去數据库根据你的搜索词去数据库里面査询数据 返回给前端

https 表示协议、www.baidu.com表示域名、s表示路径、wd=python表示查询参数

1.2.3 请求头

HTTP(HyperTextTransferprotocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP协议的详细内容请参考RFC2616。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应,相应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容

1.2.4 请求体

请求体一般承载的内容是 POST 请求中的表单数据,而对于 GET请求,请求体则为空。

1.3 响应

  • 响应状态码
    200(成功)
    403(参数不对)
    404(页面未找到)
  • 响应头
  • 响应体

二、网络请求库使用

2.1 requests库

安装环境
pycharm官网网址:https://www.jetbrains.com/pycharm/

pip install requests

版本:requests–2.28.1

1.实例引入

requests 中相应的方法就是 get 方法,非常的明确,下面通过实例来看一下:

import requests

response =requests.get('https://www.baidu.com/')
#并重新设置编码
response.encoding ='utf-8'
#获取文本数据
print('response.text: ',response.text)
#获取状态码
print('type(response): ',type(response))
print('response.status_code: ',response.status_code)
print('type(response.text): ',type(response.text))
print('response.text: ',response.text)
print('response.cookies: ',response.cookies)

控制台输出结果:

response.text:  <!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

type(response):  <class 'requests.models.Response'>
response.status_code:  200
type(response.text):  <class 'str'>
response.text:  <!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

response.cookies:  <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>

2、GET请求

import requests

params ={
"age": "18",
"name": "qi"
        }
# age=18&name=xialuo 使用params 可以自动组装参数
# res =requests.get('http://httpbin.org/get',params=params)
headers = {
'qi':'xxxxxx'
}
age = 19
res = requests.get(f"http://httpbin.org/get?age={age}&name=qi",headers=headers)
print(res.text)

res.text 接收文本数据
res.content 接收非文本数据
res.json 接收 json格式数据转字典

控制台输出结果:

{
  "args": {
    "age": "19", 
    "name": "qi"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "Qi": "xxxxxx", 
    "User-Agent": "python-requests/2.28.2", 
    "X-Amzn-Trace-Id": "Root=1-65e1f6fe-7547301641abcc901fb43d2c"
  }, 
  "origin": "223.73.4.55", 
  "url": "http://httpbin.org/get?age=19&name=qi"
}
2.1 爬虫案例

豆瓣电影地址:https://movie.douban.com

# 豆瓣电影
import requests

# 地址
url="https://movie.douban.com/j/search_subjects"
# 查询参数
params = {
    "type":"movie",
    "tag": "热门",
    "page_limit": "10",# 每页条数
    "page_start": "0",# 起始记录
}
# 请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
}
# 请求发送 响应接收
res =requests.get(url,params=params,headers=headers)
# print(res.text)
data = res.json().get('subjects')
# print(data)
for item in data:
    print(item.get("title"))

爬虫实现翻页功能

# 豆瓣电影
import requests

page = 1
total_page = 10# 默认有10页
def get_data():
    global page
    while page <= total_page:
        # 页数转换为起始记录
        page_start = (page-1)*10

        # 地址
        url ='https://movie.douban.com/j/search_subjects'
        # 查询参数
        params = {
            "type":"movie",
            "tag": "热门",
            "page_limit": "10",# 每页条数
            "page_start": page_start,# 起始记录
        }
        # 请求头
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
        }
        # 请求发送 响应接收
        response =requests.get(url,params=params,headers=headers)
        items =response.json().get('subjects')
        for item in items:
            print(item.get("title"))

        print(f'目前采集第{page}页的数据')
        page += 1

get_data()

2、post请求

# post
import requests
data ={
    'name': 'germey',
    'age': 22
}
headers ={
'user-agent':'xxxx'
}
#data 传的是字典 json传的是Json格式
# r= requests.post("http://httpbin.org/post", data=data,headers=headers)
r= requests.post("http://httpbin.org/post", json=data,headers=headers)
print(r.text)

data 传的是表单数据
json 传的是json字符串

三、数据解析库

3.1 xpath

3.1.1 工具简介

chrome插件下载:https://chrome.zzzmh.cn/index#/search
xpath 的选择功能十分强大,它提供了非常简洁明了的路径选择表达式。另外,它还提供了超过 100 个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理等。几乎所有我们想要定位的节点,都可以用 xPath 来选择。
在这里插入图片描述
点击推荐下载即可
在这里插入图片描述

输入: //input[@id=“su”]/@value

在这里插入图片描述

官网:https://www.w3.org/TR/xpath/
安装解析引擎:

pip install lxm1

表3-1 xPath常用规则

表 达 式描述
nodename选取此节点的所有子节点
/从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
选取当前节点的父节点
@选取属性

3.2.2 案例演示

1.解析
text = '''
<div>
    <ul> 
        <li class ="item-0" ><a href="link1.html"> first item </a></li> 
        <li class ="item-1" ><a href="link2.html"> second item </a></li> 
        <li class ="item-inactive" ><a href="link3.html"> third item </a></li> 
        <li class ="item-1" ><a href="link4.html"> fourth item </a></li> 
        <li class ="item-0" ><a href="link5.html"> fifth item </a></li>
    </ul>
</div>
'''

# xpath工具包
from lxml import etree
# 可以传网页html
html = etree.HTML(text)  # 初始化操作 让xpath可以匹配上
result = etree.tostring(html)
print(result.decode('utf-8'))
2 节点操作

我们一般会用 //开头的 xpath 规则来选取所有符合要求的节点。这里以前面的 HTML文本为例,如果要选取所有节点,可以这样实现:

result = htm1.xpath(‘//*’)
这里使用 * 代表匹配所有节点,也就是整个 HTML 文本中的所有节点都会被获取。可以看到,返回形式是一个列表,每个元素是 Element 类型,其后跟了节点的名称,如 html、body、div、ul、li、a 等,所有节点都包含在列表中了。

3 子节点
resu1t = htm1.xpath('//1i/a')
result=htm1.xpath('//1i/a/text()') # 提取数据
result= htm1.xpath('//1i/a/@href')# 属性值
4 指定节点获取
result =htm1.xpath('//li[@class="item-0"]/a/text()')
print(result)
5 找翻页元素

找翻页元素(下一页)的三种方法

  1. //div[@class=“page”]/a[last()-1]/@href
  2. //div[@class=“page”]/a[text()=“下一页>”]/@href
  3. F12 >>> 找到下一页对应标签 >>> 右键点击copy >>> 选择copy XPath
6 案例演示
  • 说明:提取当前网站的首页标题信息,要求使用xpath解析器
# 长沙晚报实战
import requests
from lxml import etree

maps = lambda x :x[0] if x else x

def get_data():
    headers = {
        'user-agent': 'xxxxx'
    }
    url = 'https://www.icswb.com/channel-list-channel-162.html'
    res = requests.get(url,headers=headers)
    # print(res.text)
    html = etree.HTML(res.text)
    li = html.xpath('//ul[@id="NewsListContainer"]/li')
    for ii in li:
        title = ii.xpath('./h3/a/text()')
        # print(title)
        # href = ii.xpath('./a/@href')
        href = maps(ii.xpath('./a/@href'))
        print(href)

if __name__ =='__main__':
    get_data()

四、数据存储库

4.1 CSV 文件存储

CSV,全称为 Comma-Separated Values,中文可以叫作逗号分隔值或字符分隔值,其文件以纯文本形式存储表格数据。该文件是一个字符序列,可以由任意数目的记录组成,记录间以某种换行符分隔。每条记录由字段组成,字段间的分隔符是其他字符或字符串,最常见的是逗号或制表符。不过所有记录都有完全相同的字段序列,相当于一个结构化表的纯文本形式。它比 Excel 文件更加简洁,XLS文本是电子表格,它包含了文本、数值、公式和格式等内容,而CSV中不包含这些内容,就是特定字符分隔的纯文本,结构简单清晰。所以,有时候用 CSV来保存数据是比较方便的。本节中,我们来讲解 Python 读取和写入CSV文件的过程。

1.写入

这里先看一个最简单的例子:

import csv

# 单行写入数据 数据是列表形式
with open('data.csv', 'w')as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['id','name','age'])
    writer.writerow(['10001','mike', 20])
    writer.writerow(['10002','Bob',22])
    writer.writerow(['10003','Jordan',21])

首先,打开 data.csv 文件,然后指定打开的模式为w(即写入),获得文件句柄,随后调用 csv 库的 writer 方法初始化写入对象,传入该句柄,然后调用 writerow方法传入每 行的数据即可完成写入。

2.多行写入

调用 writerows 方法同时写入多行,此时参数就需要为二维列表,例如:

import csv
# 多行写入数据
# newline='' : 每行记录不换行
with open('datas.csv', 'w', newline='')as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['id','name','age'])
    writer.writerows([['10001','mike', 20],['10002','Bob',22],['10003','Jordan',21]])

3.爬虫案例

# 入库csv-采集腾讯实践

import requests
import csv
def get_data():
    url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1709433623178&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=python&pageIndex=1&pageSize=10&language=zh-cn&area=cn'
    res = requests.get(url)
    print(res.text)
    res = requests.get(url)
    items = res.json()
    datas = list()
    for data in items.get('Data')['Posts']:
        RecruitPostName = data.get('RecruitPostName')
        LocationName = data.get('LocationName')
        Responsibility = data.get('Responsibility')
        datas.append([RecruitPostName,LocationName,Responsibility])
    with open('tx.csv', 'w', encoding='utf-8',newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(['岗位', '地区', '简介'])
        writer.writerows(datas)
        print("数据写入完毕!")

if __name__ == '__main__':
    get_data()

五、爬虫进阶

1.逆向声明

1.1 为什么要学逆向

  • 头部签名验证
    alR0cHM6Ly93d3cub2tsaW5rLmNvbs96aC1jbi9idGMvdHetbGlzdD9saW1pdD0yMCZwYWdITnVtPTE=
  • 请求参数签名验证
    aHR0CHM6Ly93d3cu24vcmFuav9DDmRwvdw50cnkvY24v22VucmUyMzY=
  • cookie验证
    аHR0CHM6Ly93d3C4ZHNZHQuZ292Lm1L300X0NOL3BnX2hvbWU=
  • 响应数据验证
    aHR0cHM6Ly9n23252ncu2mou2292LmNuL2j1c2luZXNzL2xPc3QV

2.JavaScript 是脚本语言

  • JavaScript 是一种轻是级的编程语言
  • JavaScript 是可插入 HTML 页面的编程代码。
  • JavaScript 插入 HTML页面后,可由所有的现代浏览器执行
  • JavaScript 很容易学习

2.1 JS基本功

提示:如果听不懂上课内容,建议可以先单独学习补全JS的相关课程在进行观看。

2.1.1.如何在Pycharm里面运行 JS

任何的编程语吉想要执行都需要有一个好的环境,python如此、JjavaScript也是如此。

2.1.2 node

Node.js 是一个基于Chrome v8引擎的 Javascript 运行
下载: http://nodejs.cn/download/

2.1.3 注释

单行注释以 //开头
多行注释以 /* 开始,以 */ 结尾

2.2 变量和数据类型

一、var 的使用以及作用域

(1).作用域是指函数或变量的可供访问的范围。
(2).var可以定义全局变量和局部变量
(3).var的作用域主要和函数的定义有关

  • 1.全局作用域
    如果是在任意函数的外部声明var变量,其作用域是全局的;
  • 2.局部(函数)作用域
    如果是在函数内部声明var,其作用域是局部的,只能在函数内部被访问;
    对其他块定义没有作用域,比如if、for,这就会导致外部同名变量可以随意修改在If/for内走义的变量
  • 3.var 的声明与变量提升
    在使用变量前,需要先对变量进行声明,如果只声明、未赋值,则会初始化值为undefined。
    var可以修改,也可以被重复声明。当对var 进行重复声明时,后面的变量可以覆盖前面的变量,相当于变量重置。
    var的变量提升: JS引擎在预编译代码时,会优先获取所有被var声明的变量和函数,将它们放在代码的头部然后从上到下执行。

与代数一样,JavaScript 变量可用于存放值(比如x=5)和表达式(比如 z=x+y)。JavaScript 变量有很多种类型,但是现在,我们只关注数字和字符串

var pi=3.14;
//如果你熟悉 ES6,pi 可以使用 const 关键字,表示一个常量
// const pi = 3.14;
var person="John Doe";
var answer='Yes I am!'
//先声明再赋值
var carname;
carname="Volvo"
二、let 的使用以及作用域

(1).let允许声明一个作用域被限制在 块级中的变量、语句或者表达式。与var 关键字不同的是, let声明的变量只能是全局或者整个函数块的。
(2).let声明的变量只在它所处的代码块内有效,属于块级作用域。块是由{} 界定的。
(3).let 可以被修改,但不能被重复声明。
(4).let不存在变量提升
(5).暂存性死区

三、const 的使用以及作用域

(1).像let声明一样,const声明只能在声明它们的块级作用域中访问
(2).const声明一个只读的常量,这意味着声明后的常量不能被修改并且不能被重复声明,这也意味着const声明时就必须初始化,不能等到之后赋值。
所以,当我们修饰的标识符不会被再次赋值时,就可以使用const来保证数据的安全性。

四、总结
  • 作用域:
    var声明的是全局作用域或函数作用域;而let和const 是块作用域。
  • 声明初始化:
    var和let在声明的时候可以不进行初始化;而 const 在声明的时候必须初始化。
  • 修改与重复声明:
    var在可以修改和重复声明;而let只能修改,不能在同一作用域下重复声明;const声明常量不可修改也不可重复声明。
  • 变量提升:
    var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined;let和const 不存在变量提升,即它们所声明的变量定要在声明后使用,否则会报错。
  • 暂存性死区:
    var不存在暂时性死区;let和const存在暂存性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

2.3 Js 函数语法

函数就是包表在花括号中的代码块,前面使用了关键词 function:

function functionname(){
// 执行代码
}

注:JavaScript 对大小写敏感。关键词 function 必须是小写的,并且必须以与函数名称相同的大小写来调用函数。

2.3.1 有名函数
function xxs(){
    console.log('123')
}
xxs();//执行函数
2.3.2 函数赋值表达式定义函数
sss=function(a,b,c){
    console.log(a)
}
sss(1)
2.3.3 JavaScript之自执行函数\

一种理解是,自执行即自动执行,也就是所谓的立即执行函数

!(function(arg1) {
    console.log(arg1)
    console.log("Hello World!");
})(1);
//或使用~
~(function(arg1) {
    console.log(arg1)
    console.log("Hello World!");
})(1);

在前面加上一个布尔运算符(只多了一个感叹号),就是表达式了,将执行后面的代码

2.3.4 内部函数外部调用
var _x;
!(function(arg1) {
    function xl(){
        return 'qi'
    }
    _x = xl;
    console.log("Hello World!");
})(1);
console.log(_x());

2.4.作用域

变量在函数内声明,变量为局部变量,具有局部作用域。
局部变量:只能在函数内部访问
变量在函数外定义,即为全局变量。

as =123
function xxss(){
	console.1og(as)
	var ddd = 10;
}
console.1og(as)

2.5 对象

JavaScript中的对象其实就是一组数据和功能的集合。
通过new操作符后跟要创建的对象类型的名称来创建。
对象也是一个变量,但对象可以包含多个值(多个变量),每个值以name:value 对呈现。

var car ={name:"xialuo",model:500,color:"white"};

创建了对象的一个新实例

person= new object();

这里的Object相当于祖宗一样,创建Object的实例并没有什么用处。
特点:
每个Object类型的实例共有的属性和方法:

  • constructor: 保存着用于创建当前对象的函数。
  • hasOwnProperty: 用于检测给定的属性在当前对象的实例中是否存在。
  • isPrototypeOf: 用于检查传入的对象是否是当前对象的原型。
  • propertylsEnumerble: 用于检查给定属性能否使用for-in来枚举。
  • toLocaleString(): 返回对象的字符串表示。
  • toString(): 返回对象的字符串表示。
  • valueOf(): 返回对象的字符串,数值,或布尔表示。通常和toString()返回的值相同。
2.5.1 对象访问
car.name;
car['name']
2.5.2 对象方法

对象的方法定义了一个函数,并作为对象的属性存储。

var person= {
	firstName : "xl",
	lastName : "1i1i",
	id : 5566,
	fullName : function(){
		return this.firstName +" "+ this.lastName;
	}
};

注:在对象方法中, this 指向调用它所在方法的对象。

2.6 json转换

JSON.parse() //用于将一个 JSON 字符串转换为 Javascript 对象。
JSON.stringify() //用于将 javascript 值转换为 JSON 字符串。

注:经常使用在数据的处理方面,比如后台返回数据。所以后台返回的加密数据,可以使用分析JSON.parse 来找加密位置 体现在请求后
注:JSON.stringify 用在数据加密后,变成字符串传给后台服务器

//要实现从JSON字符串转换为15对象,使用S0N.parse()方法
var obj = JSON.parse('{"a": "He1lo","b": "world"}')
//要实现从JS对象转换为1SON字符串,使用JSON.stringify()方法:
var json =JSON.stringify({a:'Hello',b:'world'});

3 JS调试技巧

3.1浏览器面板补充

Elements
Network
  • 保留日志
    勾选每次刷新不会清除之前的请求
  • 停用缓存
    勾选后不会从缓存里面拉数据,方便后续JS动态调试
    在这里插入图片描述
Sources
  • page: 所有资源文件
  • filesystem: 关联本地文件
  • overrides: 可以做文件替换,比如替换JS
  • 代码段: 可以编写脚本,影响页面,代码记录
var a =document.querySelector("#su")
//可以在控制台操作 输入 a.remove()

在这里插入图片描述
右键选择在来来源面板中打开
在这里插入图片描述
右键点击要进行覆盖的文件选择Override content
出现以下
在这里插入图片描述
将自定义的html文件覆盖到index.html中,刷新百度页面即会出现对应自定义的html
在这里插入图片描述
关闭本地替换:点击Enable Local Overrides
在这里插入图片描述

调试boss网站的页面
在这里插入图片描述
在这里插入图片描述

debugger的使用
在这里插入图片描述
跳出debugger:删除代码中的debugger并保存代码+F8

Content scripts

Content scripts内容脚本:可以用来编写插件
在这里插入图片描述

Snippets

在这里插入图片描述
在Snippets中可以直接拿到网页的内容。
步骤:

  1. F12选择需要拿到的元素行右键copy
  2. 选择Copy JS path
  3. 代码:
console.log('hello world')
console.log('比如 调试Js, 这里支持测览器环境')
console.log('与浏览器里面的参数共存')
a = document.querySelector("#su")
console.log(a)

在这里插入图片描述

  • 断点介绍
    地址:https://oauth.d.cn/auth/goLogin.html
    断点:只有被执行的逻辑才可以被断住
    在这里插入图片描述
    端点模块顺序对应功能
    • 跳过子函数(次态函数) 执行 (只在主函数内一步一步执行,不进入子函数内部)
    • 进入子函数(次态函数) 执行 (在主函数内部一步一步执行,如果遇到子函数,会跳转到子函数内部一步执行)
    • 跳出当前函数,回到调用位置
    • 单步执行,会进入到函数内部更加的细致
    • 屏蔽断点

通过抓包拿到接口数据和字段:
在这里插入图片描述
进行断点调试:
在这里插入图片描述
在右侧观察属性变化:
在这里插入图片描述
点击下一步:
在这里插入图片描述
在Console中将rsaPwd的值进行替换
在这里插入图片描述
在接口中可以看到参数进行了改变
在这里插入图片描述

3.2断点讲解

作用:对数据进行监听,跟值进行分析

3.2.1 什么是断点

当乐网站运行时间轴
加载html -> 加载JS -> 运行JS初始化 -> 用户触发某个事件 -> 调用某段JS -> 加密函数 -> 给服务器发信息(XHR-SEND) -> 接收到服务器数据 -> 解密函数 -> 刷新网页渲染
示例:https://oauth.d.cn/auth/goLogin.html

  • 跳过子函数(次态函数) 执行 (只在主函数内一步一步执行,不进入子函数内部)
  • 进入子函数(次态函数) 执行 (在主函数内部一步一步执行,如果遇到子函数,会跳转到子函数内部一步一步执行)
  • 跳出当前函数,回到调用位置
  • 单步执行,会进入到函数内部 更加的细致
  • 屏蔽断点
3.2.2 DOM事件断点
  • 执行的比较靠前 距离加密函数比较远
3.2.3 XHR 断点
  • 执行比较靠后 距离加密函数相对较近 可以根据栈快速定位
    注意:非XHR发送的就断不住
    在这里插入图片描述

3.3 方法栈

栈是一种先进后出的特殊线性表结构
调用栈是解析器的一种机制,可以在脚本调用多个的函数时,通过这种机制,我们能够追踪到哪个的函数正在执行,执行的函数体又调用了哪个函数。

  • 当脚本要调用一个函数时,解析器把该函数添加到栈中并且执行这个函数。
  • 任何被这个函数调用的函数会进一步添加到调用栈中,并且运行到它们被上个程序调用的位置。
  • 当函数运行结束后,解释器将它从堆栈中取出,并在主代码列表中继续执行代码。
3.3.1 代码说明
function ps(a,b){
    return a+b
}
function pn(a,b){
    var xx= ps(a,b)
    return xx/2
}
num = pn(1,2)
console.log(num)

3.4 debug原理

案例地址:https://gaokao.chsi.com.cn/zyk/zybk/

  • 无限debbugger不会真正得死循环,而是有规律得执行逻辑,一般用定时器
Function("debugger;").call()
3.4.1 样例
<!--
无限debug
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="box"></h1>
    <script>

        var ss = document.getElementById('box')
        function ff() {
            debugger;
        }
        setInterval(ff,100);
        ss.innerHTML ="大家晚上好";
    </script>
</body>
</html>
3.4.2 浏览器过debugger

将样例在浏览器中打开,在按F12
1、当定义器运行到这个debugger 这个代码的时候,那么这个时候它为true,它肯定执行我们的debugger 代码,那我们可以(先右键选择添加条件断点)用浏览器的功能给他改成 false
在这里插入图片描述

2、右键选择一律不在此处暂停
在这里插入图片描述

3、编辑断点
写个1===0的先验条件,永远为假,就永远不会进入这个断点了。

3.4.3 方法置空

无限debugger产生的原因是第七行代码ff这个函数造成的,所以我们可以重写这个函数,使无限debugger失效,在控制台中输入 functionff(){} 即可,如图:
注:一定要在debugger进入之前

//1.
setInterval = function(){}
//2.
function ff(){}
3.4.4 修改响应又件

把JS文件保存到本地修改,修改范围主要是将debugger相关的代码删除或者改写,可以使用文件替换、抓包工具拦截方式
在这里插入图片描述

3.4.5 注入代码到 JS 文件

在控制台注入代码
站点:https://bz.zzzmh.cn/index

var _constructor= constructor;
Function.prototype.constructor =function(s){
	if(s=="debugger"){
		console.1og(s);
		return null;
	}
	return _constructor (s);
}

3.5 hook技术

Hook 是一种钩子技术,在系统没有调用函数之前,钩子程序就先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,也可以强制结束消息的传递。简单来说,修改原有的JS代码就是 Hook。
Hook 技术之所以能够实现有两个条件:

  • 客户端拥有JS的最高解释权,可以决定在任何时候注入JS,而服务器无法阻止或干预。服务端只能通过检测和混淆的手段,另 Hook难度加大,但是无法直接阻止。
  • 除了上面的必要条件之外,还有一个条件。就是JS是一种弱类型语言,同一个变量可以多次定义、根据需要进行不同的赋值,而这种情况如果在其他强类型语言中则可能会报错,导致代码无法执行。JS的这种特性,为我们 Hook 代码提供了便利。
    注意:JS 变量是有作用域的,只有当被 hook 函数和 debugger 断点在同一个作用域的时候,才能 hook 成功。
3.5.1 Hook步骤:
  • 1寻找hook的点
  • 2编写hook逻辑
  • 3 调试
    注:最常用的是hook cookie
3.5.2 hook 方法

站点:https://fanyi.youdao.com/index.html
我们知道在 Javascript 中JSON.stringify()方法用于将]avaScript对象或值转换为JSON字符串,JSON.parse()方法用于将一个JSON 字符串转换为JavaScript 对象,某些站点在向 web 服务器传输用户名密码时,会用到这两个方法

(function(){
    var _parse = JSON.parse;
    JSON.parse = function(ps){
        console.log("Hook JSON.parse-->", ps);
        debugger;
        return _parse(ps);
    }
})();

首先定义了一个变量 _parse保留原始 JSON.parse方法,然后重写 JSON.parse方法,遇到 JSON.parse方法就会执行 debugger 语句,会立即断下,最后将接收到的参数返回给原始的 JSON.parse方法进行处理,确保数据正常传输

  1. 在控制台添加钩子,只要代码中用到JSON.parse就会被hook监测到
  2. 回车翻译单词,注意一个单词只能调用一次
    在这里插入图片描述
    在这里插入图片描述
    注:transformResponse在传递给 then/catch前,允许修改响应数据
3.5.3 hook XHR请求

案例地址: https://www.qimai.cn/
定义了一个变量 open 保留原始 XMLHttpRequest.open 方法,然后重写 XMLHttpRequest.open 方法,判断如果md 字符串值在 URL里首次出现的位置不为-1,即 URL里包含 analysis 字符串,则执行 debugger 语句,会立即断下。

//如果是正数 表示存在里面
// 如果是-1 表示不在里面
(function() {
    var open = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function(method, url, async) {
        if (url.indexof("analysis") != -1) {
            debugger;
        }
        return open.apply(this, arguments);
    };
})();

Interceptors-拦截器

  • 请求拦截器: 在发送请求之前,可以借助一些函数来对请求的内容和参数做一些检测。若有问题可以直接取消请求。
  • 响应拦截器: 当服务器返回响应数据时,响应拦截器会在我们拿到结果前预先处理响应数据。例如对响应数据做一些格式化处理,或者当响应失败时,可以做一些失败提醒和纪录。
//npm install axios
axios = require('axios')
//设置请求拦酸器
axios.interceptors.request.use(function(config){
    console.log('请求拦截器 成功')
    config.timeout = 2000;//修改请求config
    config.headers['sign']='lili'
    return config;
},function(error){
    console.log('请求拦截器 失败')
    return Promise.reject(error);
});
//设置响应拦畿器
axios.interceptors.response.use(function(response){
    console.log('响应拦截器 成功')
    console.log('调解密函数进行解密数据')
    //return response;
    //return response.data;//修改响应数据
        return {'name':'test'}
},function(error){
    console.log('响应拦截器 失败')
    return Promise.reject(error);
});
//发送请求
axios.get('http://httpbin.org/get').then(res=>console.log(res))

美团外卖逆向分析

地址:https://h5.waimai.meituan.com/

加载器案例

var ps;
!function (t){
    // 加载器
    var e= {};
    function i(n){
        if (e[n])
            return e[n].exports;
        var s= e[n]={
            i: n,
            l: !1,
            exports: {}
        };
        return t[n].call(s.exports,s,s.exports,i),
        s.l = !0,
        s.exports
    }
    // i(200)
    ps = i
}({
    'xl':function(){
        console.log('xlxlxlxl')
        return "xl"
    },
    100:function(t,e,i){
        console.log('对密码进行加密')
        return 'hello world'
    },
    200:function(){
        console.log('对密码进行解密')

    }
    })
//console.log(ps('xl'));
console.log(ps(100));

有道翻译逆向分析

链接:https://fanyi.youdao.com/index.html#/

解密方法

Po["a"].decodeData(o, Wo["a"].state.text.decodeKey, Wo["a"].state.text.decodeIv)

o为密文

Wo["a"].state.text.decodeKey:
'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'
Wo["a"].state.text.decodeIv:
'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'
加密方法解析
R = (t,o,n)=>{
                if (!t)
                    return null;
                const a = e.alloc(16, y(o))
                  , i = e.alloc(16, y(n))
                  , r = c.a.createDecipheriv("aes-128-cbc", a, i);
                let s = r.update(t, "base64", "utf-8");
                return s += r.final("utf-8"),
                s
            }

通过e.alloc(16, y(o))追到e = b639
在这里插入图片描述

c.a = 1c46
在这里插入图片描述

  • 21
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值