前言
作为网页三剑客之一,在爬虫领域js逆向用的比较多,所以有必要学习和了解。
数据爬取是和网页打交道,自然需要能够看懂它传送的信息~
1. JS概述
JavaScript(简称“JS”)是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。 虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。
2. JS的引入方式
通过script标签引入
引入方式1:
通过<script>标签进行导入,它可以写在head里,也可以写在body里
>
下面来看一个简单的js导入示例:
我们可以在pycharm中new一个html文件,让它弹一个框,以及打印1+1的结果
● alert:弹框行为
● console.log:控制台打印,相当于python的print
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
alert(123); /* alert:弹框行为 */
console.log(1 + 1) /* console.log:控制台打印 */
</script>
</body>
</html>
1+1并没有显示出来,因为代码是从上到下执行的
所以点完确定,在浏览器上点确定后,就可以看到控制台输出“2”
通过js文件引入
与之前学习的css一样,也可以将js作为一个静态文件,引用时直接导入
>
将上述代码中的弹框行为+控制台打印行为,copy出来新建一个js文件:
pycharm中new -> JavaScript Flie
在html文件head里,直接进行导入js:<script src="dindex.js"></script>
我这边是直接将js和html文件放在同一路径下,直接导入文件名即可
执行后是一样的效果:
JS注释
js的单行注释:两个斜杠//;快捷键:选中内容ctrl+/
js的多行注释:/* */;快捷键:选中内容ctrl+shift+/
3. JS的基本语法
学习任何一门编程语言,都是从变量、数据类型、运算符开始:
比如 1+1=2,1是一个数字类型,+是一个科学运算符,结果等于2是个变量、
再到逻辑控制语句、函数等等,JS也是一样。
>
但是有了python基础之后,再来学js会相对简单
下面,让我们正式开启JS的学习之旅吧~
3.1 JS的变量
变量赋值:
● 局部变量关键字:var声明变量,新版是let
● 全局变量:可以像python一样自定义
>
变量命名规则:和python大致一样
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//变量赋值:局部关键字var声明变量,新版是let
var x = 10;
let y = 10;
/* 也可以像python一样,自定义变量,自定义的都是全局变量
变量名命名规则与python大致一样 */
z = 100;
</script>
</head>
<body>
</body>
</html>
3.2 JS的数据类型
● js的基本数据类型:整形&浮点型、字符串类型、bool类型(必须是小写的false、ture)
>
● js的进阶数据类型:[]、{}都叫object,即数组;
与python不同的是,在{}数组中,键作为一个属性,可以不加引号,也不会报错
从控制台打印结果可以看出,info2的数组,即便加了引号,也默认取消了引号
且键作为属性,查找元素时,可以直接.属性名,也可以像python一样切片取元素
object也像python字典一样,属性值可以多层嵌套属性和值,即深层次object
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//基本数据类型
let age = 20;
let pai = 3.1415926
let name = "小明"
let secondName = "ming"
let isMarride = "false" //bool值首字母小写
//进阶数据类型:[] object
let names = ["hello,world"]
let info = ["wang",20,"male"]
console.log(typeof info) //查看数据类型
console.log(info[0],info[1]) //取该数组的元素
var info2 = {"name":"小明","age":20,"gender":"male"}
console.log("info2", info2)
console.log(typeof info2)
console.log("::",info2["name"])
var info3 = {name:"小美",age:20,gender:"male"}
console.log(typeof info3)
console.log("::",info3.name) //键作为属性,可以直接.属性名
</script>
</head>
<body>
</body>
</html>
3.3 JS的运算符
基本运算符
科学运算符:+ - * / (即加减乘除,不做演示)
● 如果是数字+字符串:会自动将数字转换为字符串,得到字符串拼接效果
自增运算符
自增运算符有两个:+=、++
● +=:与python一样,自增操作,可以加任意数字
● ++:自增操作,只能+1;在json中自增1比较场景,所以单拎出来一个
逻辑运算符
逻辑运算符有:> < <=. >=. ===. !== =(均返回bool值)
● 大于:>
● 小于:<
● 小于等于:<=
● 大于等于:>=
● 等于:=如果是字符串类型的数字与数字比较,会返回ture,js会自动将数字转换为字符串
● 完全等于:===,如果数字与字符串类型的数字比较,不想要字段转换,可以用===
● 等于:!=
与或非运算符
与或非运算符有三个:&& || !
● &&:表示and
● ||:表示or
● !:表示not
>
示例如下, ||和!同理:
3.4 JS流程控制语句
与python一样,JS也有流程控制语句
不同的是:
python是通过冒号及4个缩进,来严格控制语句,少写冒号或缩进不对都会报错
在js中,不会因为缩进问题报错,只要每一行的最后加上;就可以正常执行语句
js分支语句
语句格式如下:
if(条件){ // 条件为true时,执行的代码
else{// 条件为false时,执行的代码}
代码示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//分支语句:
var age = 18;
if (age >= 18){console.log("成人区")}
else {console.log("未成年区")}
</script>
</head>
<body>
</body>
</html>
switch语句
像上面的if、else语句,由于是层层遍历,执行起来性能比较差,所以有了switch语句:
语法如下:
case 结果1:
// 满足条件执行的结果是结果1时,执行这里的代码..
break;
case 结果2:{
// 满足条件执行的结果是结果2时,执行这里的代码..
break;
...
default:
// 条件和上述所有结果都不相等时,则执行这里的代码 }
比如我们打印一个“hi,星期五”
示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//switch语句:
var week = 5
switch (week){
case 1:console.log("hi,星期一");break;
case 2:console.log("hi,星期二");break;
case 3:console.log("hi,星期三");break;
case 4:console.log("hi,星期四");break;
case 5:console.log("hi,星期五");break;
case 6:console.log("hi,星期六");break;
}
</script>
</head>
<body>
</body>
</html>
当星期五的后面去掉break,就会一直往下走
default:输入值判断,都不满足的时候执行
js_whlie循环
与python不同的是,在js中:whlie循环、for循环都是条件循环
>
语法:
while(循环的条件){ // 循环条件为true的时候,会执行这里的代码 }
>
例如:循环打印1~10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//循环语句:循环打印1~10
let count = 0;
while (count<10){
count++; //前三行限定了循环条件
console.log(count);} //业务逻辑语句,可以打印数字,也可以打印hlleo world
</script>
</head>
<body>
</body>
</html>
JS_for循环
与python不同的是,在js中:whlie循环、for循环都是条件循环
所以本质上,js的whlie循环、for循环没有太大区别,for循序只是修饰了whlie循环
>
语法:
for(1.声明循环的开始; 2.条件; 4. 循环的计数){
// 3. 循环条件为true的时候,会执行这里的代码 }>
将上述循环打印1~10的代码改为for循环:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//for循环,循环三要素:初始语句、判断表达式、步进语句
for (var count = 0;count <10;count++){
console.log(count) //业务逻辑代码
}
</script>
</head>
<body>
</body>
</html>
3.6 JS的函数
● js函数声明关键字:function
● 与python不同的是:函数调用时,调用语句可以放在最函数声明之前,可以放在最后
>
代码示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//调用:
foo()
//声明函数:
function foo(){
console.log("foo……")
}
//第二种:函数传参
function add(x,y){
return x +y
}
add(10,20) //传参,10赋x,20赋给y
console.log(add(10,20))
</script>
</head>
<body>
</body>
</html>
匿名函数
匿名函数:即函数没有名称
语法:(function(//形参){
//函数体})(//实参)
>
示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//匿名函数:即函数没有名称
const result = (function (x,y){
return x + y})(3,5)
console.log(result)
</script>
</head>
<body>
</body>
</html>
3.7 JS的字符串内置方法
JS字符串常见操作方法如下:
● console.log( str.length ):求字符串长度
● str.toUpperCase():将字符串全部转换为大写
● str.toLowerCase():将字符串全部转换为小写
● str.slice(3,6):字符串切片,含头不含尾
● str.split(" "):将字符串按照逗号分隔
● str.trim():去除字符串两边多余的空格>
使用示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>字符串内置方法</title>
<script>
let str = "Hello World";
console.log(str.length);//求字符串长度
console.log(str.toUpperCase()) //将字符串全部转换为大写
console.log(str.toLocaleLowerCase()) //将字符串全部转换为小写
console.log(str.slice(0,3)) //字符串切片,含头不含尾
console.log(str.slice(-3,)) //取字符串最后三位
var citys = "深圳 天津 北京 上海"
console.log(citys.split(" ")) //将字符串按照空格分隔
citysArray = citys.split(" ") //将分隔后的字符串重新赋给一个变量
console.log(citysArray.length) //打印有几个城市
var name = " 小明 "
console.log(name.length)
console.log(name.trim()) //去除字符串两边多余的空格
</script>
</head>
<body>
</body>
</html>
3.8 JS数组的内置方法
JS数组常见操作方法如下:
● arr.push():给数组后面追加成员
● arr.pop():删除最后一个成员作为返回值
● arr.shift() :将数组的第一个元素删除
● arr.unshift(0):unshift是将value值插入到数组的开始
● arr.reverse():数组反转
● arr.slice(开始下标,结束下标):数组切片
>示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>数组的内置方法</title>
<script>
var arr = [1,2,3,4,5]
console.log(arr[1]) //查找第二位元素
console.log(arr.slice(2)) //从第二位至全面全部元素
//向数组末尾插入/删除值:
arr.push(6) //默认向数组末尾插入值
console.log(arr)
arr.pop() //默认删除数组最后一个值
console.log(arr)
//向数组的首位插入/删除值
arr.unshift(0) // 在数组首位添加一个元素
console.log(arr)
arr.shift() //删除首位的元素
console.log(arr)
arr.reverse() //数组翻转
console.log(arr)
</script>
</head>
<body>
</body>
</html>
高阶函数
filter
filter() :高阶函数, 对数组的每一个成员进行过滤,返回符合条件的结果
>
如下示例:对arr数组中的偶数进行保留
以下是使用匿名函数、不使用匿名的两种写法对比
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>高阶函数</title>
<script>
//var arr = [4, 6, 5, 7];
/* //声明一个函数:只能串一个参数:item
function filterOushu(item){
return item % 2 === 0 //业务逻辑语句:item除以2等于0的即为偶数,就保留下来
}
//filter内置的循环,将数组中每个参数作为值传给item
var ret = arr.filter(filterOushu)
console.log(ret) */
//也可以使用匿名函数:
var arr = [4, 6, 5, 7];
var ret = arr.filter(function (item){
return item % 2 === 0 })
console.log(ret)
</script>
</head>
<body>
</body>
</html>
map
map(): 对数组的每一个成员进行处理,返回处理后的每一个新成员
>
如下示例:对arr数组中的所有元素求平方
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>高阶函数</title>
<script>
//map:对数组中的所有元素求平方
var arr = [4, 6, 5, 7];
var ret = arr.map(function (item){
return item * item })
console.log(ret)
</script>
</head>
<body>
</body>
</html>
splic:
splice同时具备增、删、改的功能:
● splice(起始索引,删除元素的个数):纯删除元素,只能连续删除
● splice(起始索引,0,“新元素”):第二个值为0,同时后面有新元素,表示在指定位置增加元素
● splice(起始索引,删除元素的个数,“新元素”):在指定位置先删除,再增加元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>高阶函数</title>
<script>
//splice方法:删除、插入、替换
var arr = ["a","b","c","d"]
arr.splice(1,2) //从第一个元素后面删除2个元素,只能连续删
console.log(arr)
var arr2 = ["a","b","c","d"]
arr2.splice(1,0,"B") //第二个值为0,表示插入新元素
console.log(arr2)
var arr3 = ["a","b","c","d"]
arr3.splice(1,2,"D","E") //从第一个元素后面删除2个元素,再插入DE
console.log(arr3)
</script>
</head>
<body>
4. Josn序列化和反序列化
基本概述
序列化:
将某种编程语言支持的数据类型对象,做一个格式化字符串,从而进行磁盘存储或者网络传输。
>
反序列化:
将能够进行存储或者网络传输的某种格式化字符串转换成编程语言能够识别的数据类型。
>
在进行爬虫时,拿到的都是json数据,所以是必须了解的知识点。
json
json是一个标准的数据交换格式
json是从JavaScript里提炼出来的一种数据交换格式,不属于任何一种编程语言
几乎所有的编程语言都能够使用json进行字符串格式的交换(即序列化、反序列化)
>
json支持的数据类型:
" ":字符串类型
123:数字类型
[]:列表类型
{} :键值类型
null:空值
bool:true、false
json格式化方法
js中两个对json格式化转换方法:
● JSON.parse(obj) :json格式转换为数组类型,即进行反序列化
●JSON.stringify(str):转换为json格式,即进行序列化
下面,我们将一个接收到的json字符串,转换为数组类型:
下面我们将一个数组,进行格式化转为json字符串
5. DOM操作
DOM (document Object Model: 文档对象模型)
JS的标签查找
直接查找标签
● document.getElementsByTagName("标签名"):得到的是一个dom数组
● document.getElementById("id值"):得到的是一个dom对象
● document.getElementsByClassName("类名"):得到的是一个dom数组
按照calss类名查找,一般用的比较多
>
下面看一个实例
让js执行弹窗、悬浮弹窗监听事件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="c1">click1</div>
<div class="c2">click2</div>
<div class="c3">click3</div>
<script>
dom = document.getElementsByClassName("c1")[0]
console.log(dom)
dom.onclick = function (){
alert(123) //对c1标签绑定一个监听事件:当点击onclick时,弹个窗显示123
}
/* dom.onmouseover = function (){
alert(123) //对c1标签绑定一个监听事件:当点击onclick时,悬浮弹窗显示123
} */
</script>
</body>
</html>
当鼠标点击click1时,就会弹窗显示123
而点击 click2、click3时不会有弹窗,因为绑定的dom指向的是c1这个calss
导航查找标签
● elementNode.parentElement // 父节点标签元素:得到一个dmo对象
● elementNode.children // 所有子标签:得到的是一个dom数组,可能有多个子标签
● elementNode.firstElementChild // 第一个子标签元素:得到一个dmo对象
● elementNode.lastElementChild // 最后一个子标签元素:得到一个dmo对象
● elementNode.nextElementSibling // 下一个兄弟标签元素:得到一个dmo对象
● elementNode.previousElementSibling // 上一个兄弟标签元素:得到一个dmo对象
下面以京东为例,我们使用上述部分方法:
先找到一个标签,再基于它找到其父、子、兄弟标签
CSS选择器
● document.querySelector("css选择器") :
根据css选择符来获取查找到的第一个元素,返回标签对象(dom对象)
● document.querySelectorAll("css选择器"):根据css选择符来获取查找到的所有元素,返回数组
使用以上css选择器方法,查找京东的标签
事件绑定
静态绑定 :直接把事件写在标签元素中
语法格式:dom.on事件 = function(){}
形参不能是this
动态绑定:在js中通过代码获取元素对象,然后给这个对象进行后续绑定
语法格式:dom.on事件 = function(){}
this直接用
>
示例如上(直接查找标签的代码示例)
JS操作标签
文本操作
文本操作:<标签名 属性1=“属性值1” 属性2=“属性值2”……>文本</标签名>
一般为闭合标签
★ js操作dom的特性:局部刷新
如下示例:
对calss标签为c1的属性,进行绑定onclick(单击事件),当点击文本内容“click1”时,即显示“hello ”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="c1">click1</div>
<div class="c2">click2</div>
<div class="c3">click3</div>
<script>
dom = document.getElementsByClassName("c1")[0]
console.log(dom)
//onclick:单击事件
dom.onclick = function (){
//打印当前标签的文本值
//console.log(this.innerHTML)
this.innerHTML = "hello"
}
</script>
</body>
</html>
value操作
像input标签,select标签以及textarea标签是没有文本的,但是显示内容由value属性决定
如下示例:
在Input标签中,用户输入用户名,输入完毕,光标移开之后,即获取输入的value进行打印:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="c1">click1</div>
<div class="c2">click2</div>
<div class="c3">click3</div>
<p>用户名:<input id="i2" type="text"></input></p>
<script>
dom = document.getElementById("i2")
dom.onblur = function (){
console.log(this.value)
}
</script>
</body>
</html>
样式操作
如下示例:
给dom再增加一个css样式,点击calss标签为c1的属性时,让显示内容变为红色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="c1">click1</div>
<div class="c2">click2</div>
<div class="c3">click3</div>
<p>用户名:<input id="i2" type="text"></input></p>
<script>
//js:选择标签+操作标签
dom = document.getElementsByClassName("c1")[0]
console.log(dom)
//onclick:单击事件
dom.onclick = function (){
//打印当前标签的文本值
//console.log(this.innerHTML)
this.innerHTML = "hello" //点击calss为c1的标签时,让显示内容变为hello
//css操作:
this.style.color = "red" //点击calss为c1的标签时,让显示内容变为hello,同时为红色
}
dom2 = document.getElementById("i2")
dom2.onblur = function (){
console.log(this.value)
this.value = "小明" //value赋值
}
</script>
</body>
</html>
6. jQuery
jQuery是一个快速、简洁的JavaScript架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是"少写,多做”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和阿贾克斯交互。
iQuerv的核心特性可以总结为: 具有独特的链式语法和短小清晰的多功能接口,具有高效灵活的Css选择器,并且可对CSS选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件。iQuev兼容各种主流浏览器,如E 6.0+、FF 1.5、Safari 2.0+、Opera9.0+等。
简单来说:jQuery可在DOM操作的基础上做了一些封装,让js的一些操更简单。
文本操作
● S("选择符”).html() : 读取指定元素内容,如果s()函数获取了有多个元素,提取第一个元素
● $("选择符”).htm1(内容) :修改内容如果)函数获取了多个元素,则批量修改内容
一个简单的标签查找,设定点击事件的示例:
>
jQuery只是js中的一个库,执行js代码时,浏览器解析时并不认识jQuery
所以代码中,需要先导入jQuery到js中
● 方式1:<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"> </script>
● 方式2:也可以直接将jquery放在本地文件中,直接引用<script src="path"> </script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul class="title">
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
<!-- 需要先导入jquery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js">
</script>
<script>
//$表示query,查找ul标签里所有li的标签,点击文本内容都弹窗显示123
$("ul li").click(function (){
alert(123) //内部的循环机制,支持绑定多个事件
})
</script>
</body>
</html>
★ 7. Ajax请求
Ajax概述
● Ajax,一般中文称之为:"阿贾克斯",是英文 “Async Javascript And Xml”的简写,译作:异步js和xml传输数据技术。
>
● ajax的作用: ajax可以让js代替浏览器向后端程序发送**`http`**请求,与后端通信,在用户不知道的情况下操作数据和信息,从而实现页面局部刷新数据/无刷新更新数据。
所以开发中ajax是很常用的技术,主要用于操作后端提供的`数据接口,从而实现网站的`前后端分离。
>
● ajax技术的原理是实例化js的XMLHttpRequest对象,使用此对象提供的内置方法就可以与后端进行数据通信。
数据接口
数据接口,也叫api接口,表示`后端提供`操作数据/功能的url地址给客户端使用。
客户端通过发起请求向服务端提供的url地址申请操作数据【操作一般:增删查改】
同时在工作中,大部分数据接口都不是手写,而是通过函数库/框架来生成。
>
常见的向服务器发送请求的方式:
1. 地址栏请求:get
2. a标签:get
3. form表单 :get 、post
4.ajax请求(占比最多)
前三种属于一个类型,共同特点是:同步请求,页面刷新
ajax属于异步请求,局部刷新
一个简单的示例,来看什么是ajax异步请求:
例如:进行注册网易163邮箱时,输入用户名都会自动效验,是否已存在
而这个过程,注册页面并没有被刷新,但在输入完毕、光标移开之后就会自动提示,该邮箱地址已被使用,这就是一个典型ajax请求。