20240421
1.网易云爬取
import zlib
# pip install PyExecJS
import execjs
import requests
import time
import hashlib
import base64
import os
import json
import re
headers = {
"authority": "music.163.com",
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://music.163.com",
"pragma": "no-cache",
"referer": "https://music.163.com/",
"sec-ch-ua": "^\\^Not_A",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "^\\^Windows^^",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"
}
def get_js():
f = open("tests.js", 'r',encoding='utf8')
line = f.readline()
htmlstr = ''
while line:
htmlstr = htmlstr+line
line = f.readline()
return htmlstr
def get_des_psswd(e):
js_str = get_js()
ctx = execjs.compile(js_str)
#这里hello为js文件里的函数,e为向hello这个函数里传递的参数
#这里我们的e这个形参主要用来传递歌曲的id,这样我们只需要向该函数传递不同的歌曲Id,即可返回不同的下载链接
return (ctx.call('hello',e))
def get_song_url(song_id):
token = get_des_psswd(song_id)
url = "https://music.163.com/weapi/song/enhance/player/url/v1"
params = {
"csrf_token": ""
}
data = {
"params": token[0],
"encSecKey": token[1]
}
print(data)
response = requests.post(url, headers=headers,params=params, data=data).json()
song_url = response['data'][0]['url']
return song_url
def save_song(song_url,song_path):
song_response = requests.get(song_url).content
op = open('{}.mp3'.format(song_path),'wb')
op.write(song_response)
op.close()
def get_song_id(album_id):
album_url = 'https://music.163.com/playlist?id={}'.format(album_id)
album_source = requests.get(album_url,headers=headers).text
result = re.findall('<a href="/song\?id=(\d+)">(.*?)</a>',album_source)
return result
def main():
song_id_and_song_name = get_song_id(158010361)
if not os.path.isdir('158010361'):
os.mkdir('158010361')
for song_id,song_name in song_id_and_song_name:
song_url = get_song_url(song_id)
if song_url:
song_path = "./158010361/{}".format(song_name)
save_song(song_url, song_path)
main()
2.js知识
(1)js声明,var let const 区别
console.log(s);
}
console.log(s);
};
var add = new Function(
'x',
'y',
'return x + y'
);
// 等同于
function add(x, y) {
return x + y;
}
(5)立刻调用表达式数组
函数作用域:
作用域(scope)指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。
函数内部定义的变量,会在该作用域内覆盖同名全局变量。
.......
3.eval加密网站解决
基本用法
eval
命令接受一个字符串作为参数,并将这个字符串当作语句执行。
eval('var a = 1;');
a // 1
4.强制转换
强制转换主要指使用Number()
、String()
和Boolean()
三个函数,手动将各种类型的值,分别转换成数字、字符串或者布尔值。
Number()
// 数值:转换后还是原来的值
Number(324) // 324
// 字符串:如果可以被解析为数值,则转换为相应的数值
Number('324') // 324
// 字符串:如果不可以被解析为数值,返回 NaN
Number('324abc') // NaN
// 空字符串转为0
Number('') // 0
// 布尔值:true 转成 1,false 转成 0
Number(true) // 1
Number(false) // 0
// undefined:转成 NaN
Number(undefined) // NaN
// null:转成0
Number(null) // 0
类似函数parseInt函数的使用
parseInt('42 cats') // 42
Number('42 cats') // NaN
String()
String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"
String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
Boolean()
Boolean()
函数可以将任意类型的值转为布尔值。
它的转换规则相对简单:除了以下五个值的转换结果为false
,其他的值全部为true
。
-
undefined
-
null
-
0
(包含-0
和+0
) -
NaN
-
''
(空字符串)
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean(true) // true
Boolean(false) // false
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
自动转换
遇到以下三种情况时,JavaScript 会自动转换数据类型,即转换是自动完成的,用户不可见。
第一种情况,不同类型的数据互相运算。
123 + 'abc' // "123abc"
第二种情况,对非布尔值类型的数据求布尔值。
if ('abc') {
console.log('hello')
} // "hello"
第三种情况,对非数值类型的值使用一元运算符(即+
和-
)。
+ {foo: 'bar'} // NaN
- [1, 2, 3] // NaN
自动转换的规则是这样的:预期什么类型的值,就调用该类型的转换函数。比如,某个位置预期为字符串,就调用String()
函数进行转换。如果该位置既可以是字符串,也可能是数值,那么默认转为数值。
由于自动转换具有不确定性,而且不易除错,建议在预期为布尔值、数值、字符串的地方,全部使用Boolean()
、Number()
和String()
函数进行显式转换。
5.Object对象函数
Object.setPrototypeOf
在 JavaScript 中用于设置一个对象的原型(即内部的 [[Prototype]] 属性)。这个方法通常用于改变对象的继承链,或者将一个对象的原型设置为 null 来防止进一步的原型继承。
下面是一个使用 Object.setPrototypeOf 方法的例子:
// 构造函数
function Animal(name) {
this.name = name;
}
// 添加一个方法到 Animal 原型上
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound.');
};
// 使用构造函数创建一个实例
const animal = new Animal('Generic animal');
// 创建另一个构造函数
function Vehicle(make, model) {
this.make = make;
this.model = model;
}
// 添加一个方法到 Vehicle 原型上
Vehicle.prototype.describe = function() {
console.log('This is a ' + this.make + ' ' + this.model + ' vehicle.');
};
// 使用构造函数创建一个 Vehicle 实例
const car = new Vehicle('Toyota', 'Corolla');
// 现在,我们将 car 实例的原型设置为 animal 实例
// 这意味着 car 将继承 animal 实例的所有属性和方法
Object.setPrototypeOf(car, animal);
// 验证原型链是否已改变
console.log(Object.getPrototypeOf(car) === animal); // 输出: true
// 由于 car 的原型现在是 animal,它继承了 speak 方法
car.speak(); // 输出: Generic animal makes a sound.
// 为了演示,我们也可以将 car 的原型设置为 null,这样它就不再有原型
Object.setPrototypeOf(car, null);
// 再次验证原型链
console.log(Object.getPrototypeOf(car) === null); // 输出: true
// 现在 car 没有原型,因此不能访问 speak 方法
car.speak(); // 输出: TypeError: car.speak is not a function
在这个例子中,我们首先定义了两个构造函数 Animal 和 Vehicle,并分别为它们的原型添加了方法 speak 和 describe。然后,我们分别使用这两个构造函数创建了 animal 和 car 实例。
接下来,我们使用 Object.setPrototypeOf 方法将 car 实例的原型设置为 animal 实例。这意味着 car 现在继承了 animal 实例的所有属性和方法。我们通过调用 car.speak() 来验证这一点,它输出了 animal 实例的名字和声音。
最后,我们再次使用 Object.setPrototypeOf 方法将 car 的原型设置为 null,这意味着 car 将不再继承任何属性和方法。当我们尝试调用 car.speak() 时,由于 car 没有 speak 方法,因此抛出了一个类型错误。
这个例子展示了 Object.setPrototypeOf 方法如何用于修改对象的原型链,以及如何通过改变原型来控制对象继承的属性和方法
Object.getOwnPropertyDescriptor
`Object.getOwnPropertyDescriptor` 方法在 JavaScript 中用于获取指定对象上给定属性的描述信息。描述信息是一个包含属性的各种元数据的对象,例如属性是否可枚举、是否可写、默认值以及 getter 和 setter 函数等。
这个方法对于深入了解对象属性的具体行为和特征非常有用,尤其是在调试或者需要精确控制对象属性时。
下面是一个使用 `Object.getOwnPropertyDescriptor` 方法的例子:
```javascript
// 创建一个对象,并定义一个属性
const myObject = {
myProperty: 'Hello, World!'
};
// 定义一个 getter 和一个 setter 函数
const getter = function () {
return this.myProperty + ' (accessed via getter)';
};
const setter = function (newValue) {
this.myProperty = newValue + ' (updated via setter)';
};
// 使用 Object.defineProperty 为对象添加一个带有 getter 和 setter 的属性
Object.defineProperty(myObject, 'accessorProperty', {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
// 使用 Object.getOwnPropertyDescriptor 获取属性描述信息
const descriptor = Object.getOwnPropertyDescriptor(myObject, 'accessorProperty');
// 打印属性描述信息
console.log(descriptor);
// 输出:
// {
// value: 'Hello, World! (accessed via getter)',
// writable: false,
// enumerable: true,
// configurable: true,
// get: [Function: getter],
// set: [Function: setter]
// }
// 直接访问属性值
console.log(myObject.accessorProperty); // 输出: 'Hello, World! (accessed via getter)'
// 修改属性值
myObject.accessorProperty = 'Goodbye, World!';
console.log(myObject.accessorProperty); // 输出: 'Goodbye, World! (updated via setter)'
在这个例子中,我们首先创建了一个对象 `myObject` 并给它定义了一个普通的属性 `myProperty`。接着,我们定义了一个 getter 函数和一个 setter 函数,并将它们与 `Object.defineProperty` 方法一起使用,为 `myObject` 添加了一个带有访问器(accessor)的属性 `accessorProperty`。
使用 `Object.getOwnPropertyDescriptor` 方法,我们获取了 `accessorProperty` 的描述信息,并打印出来。描述信息对象包含了属性的值、是否可写、是否可枚举、是否可配置以及 getter 和 setter 函数的引用。
然后,我们通过直接访问 `accessorProperty` 来触发 getter 函数,并打印出它的返回值。之后,我们尝试修改 `accessorProperty` 的值,这将触发 setter 函数,并将修改后的值打印出来。
通过这个例子,我们可以看到 `Object.getOwnPropertyDescriptor` 方法如何帮助我们获取和理解对象属性的详细信息。