Python逆向爬虫入门: 音乐加密参数 sign 逆向解析

音乐数据包分析

  1. 正常流程抓包分析数据, 找到音频链接

  2. 找到歌曲对应的数据包位置

  3. 找到 sign 加密位置

看到这里 MD5 又是 32位的 感觉是是正常的md5加密, 其实他不是的, 可以找一个MD5在线加密的测试一下, 发现好像不是, 那就只能去扣代码了, 这个代码还挺好扣的

JS代码

var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : void 0 !== global ? global : "undefined" != typeof self ? self : {};

function createCommonjsModule(e, t) {
    return e(t = {
        exports: {}
    }, t.exports),
        t.exports
}

var md5 \= createCommonjsModule((function (module) {
        !function () {
            var ERROR \= "input is invalid type"
                , WINDOW \= "object" == typeof window
                , root \= WINDOW ? window : {};
            root.JS\_MD5\_NO\_WINDOW && (WINDOW = !1);
            var WEB\_WORKER \= !WINDOW && "object" == typeof self
                ,
                NODE\_JS \= !root.JS\_MD5\_NO\_NODE\_JS && "object" == typeof process && process.versions && process.versions.node;
            NODE\_JS ? root \= commonjsGlobal : WEB\_WORKER && (root = self);
            var COMMON\_JS \= !root.JS\_MD5\_NO\_COMMON\_JS && module.exports,
                ARRAY\_BUFFER \= !root.JS\_MD5\_NO\_ARRAY\_BUFFER && "undefined" != typeof ArrayBuffer,
                HEX\_CHARS \= "0123456789abcdef".split(""), EXTRA = \[128, 32768, 8388608, -2147483648\],
                SHIFT \= \[0, 8, 16, 24\], OUTPUT\_TYPES = \["hex", "array", "digest", "buffer", "arrayBuffer", "base64"\],
                BASE64\_ENCODE\_CHAR \= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),
                blocks \= \[\], buffer8, buffer, buffer8, blocks;
            ARRAY\_BUFFER && (buffer = new ArrayBuffer(68),
                buffer8 \= new Uint8Array(buffer),
                blocks \= new Uint32Array(buffer)),
            !root.JS\_MD5\_NO\_NODE\_JS && Array.isArray || (Array.isArray = function (e) {
                    return "\[object Array\]" === Object.prototype.toString.call(e)
                }
            ),
            !ARRAY\_BUFFER || !root.JS\_MD5\_NO\_ARRAY\_BUFFER\_IS\_VIEW && ArrayBuffer.isView || (ArrayBuffer.isView = function (e) {
                    return "object" == typeof e && e.buffer && e.buffer.constructor === ArrayBuffer
                }
            );
            var createOutputMethod \= function (e) {
                return function (t) {
                    return new Md5(!0).update(t)\[e\]()
                }
            }
                , createMethod \= function () {
                var e \= createOutputMethod("hex");
                NODE\_JS && (e = nodeWrap(e)),
                    e.create \= function () {
                        return new Md5
                    }
                    ,
                    e.update \= function (t) {
                        return e.create().update(t)
                    }
                ;
                for (var t = 0; t < OUTPUT\_TYPES.length; ++t) {
                    var n \= OUTPUT\_TYPES\[t\];
                    e\[n\] \= createOutputMethod(n)
                }
                return e
            }
                , nodeWrap \= function (method) {
                var crypto \= eval("require('crypto')")
                    , Buffer \= eval("require('buffer').Buffer")
                    , nodeMethod \= function (e) {
                    if ("string" == typeof e)
                        return crypto.createHash("md5").update(e, "utf8").digest("hex");
                    if (null == e)
                        throw ERROR;
                    return e.constructor === ArrayBuffer && (e = new Uint8Array(e)),
                        Array.isArray(e) || ArrayBuffer.isView(e) || e.constructor === Buffer ? crypto.createHash("md5").update(new Buffer(e)).digest("hex") : method(e)
                };
                return nodeMethod
            };

            function Md5(e) {
                var t;
                e ? (blocks\[0\] \= blocks\[16\] = blocks\[1\] = blocks\[2\] = blocks\[3\] = blocks\[4\] = blocks\[5\] = blocks\[6\] = blocks\[7\] = blocks\[8\] = blocks\[9\] = blocks\[10\] = blocks\[11\] = blocks\[12\] = blocks\[13\] = blocks\[14\] = blocks\[15\] = 0,
                    this.blocks \= blocks,
                    this.buffer8 \= buffer8) : ARRAY\_BUFFER ? (t = new ArrayBuffer(68),
                    this.buffer8 \= new Uint8Array(t),
                    this.blocks \= new Uint32Array(t)) : this.blocks = \[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\],
                    this.h0 \= this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0,
                    this.finalized \= this.hashed = !1,
                    this.first \= !0
            }

            Md5.prototype.update \= function (e) {
                if (!this.finalized) {
                    var t, n \= typeof e;
                    if ("string" != n) {
                        if ("object" != n)
                            throw ERROR;
                        if (null === e)
                            throw ERROR;
                        if (ARRAY\_BUFFER && e.constructor === ArrayBuffer)
                            e \= new Uint8Array(e);
                        else if (!(Array.isArray(e) || ARRAY\_BUFFER && ArrayBuffer.isView(e)))
                            throw ERROR;
                        t \= !0
                    }
                    for (var r, i, s = 0, o = e.length, a = this.blocks, u = this.buffer8; s < o;) {
                        if (this.hashed && (this.hashed = !1,
                            a\[0\] \= a\[16\],
                            a\[16\] = a\[1\] = a\[2\] = a\[3\] = a\[4\] = a\[5\] = a\[6\] = a\[7\] = a\[8\] = a\[9\] = a\[10\] = a\[11\] = a\[12\] = a\[13\] = a\[14\] = a\[15\] = 0),
                            t)
                            if (ARRAY\_BUFFER)
                                for (i = this.start; s < o && i < 64; ++s)
                                    u\[i++\] = e\[s\];
                            else
                                for (i = this.start; s < o && i < 64; ++s)
                                    a\[i \>> 2\] |= e\[s\] << SHIFT\[3 & i++\];
                        else if (ARRAY\_BUFFER)
                            for (i = this.start; s < o && i < 64; ++s)
                                (r \= e.charCodeAt(s)) < 128 ? u\[i++\] = r : (r < 2048 ? u\[i++\] = 192 | r >> 6 : (r < 55296 || 57344 <= r ? u\[i++\] = 224 | r >> 12 : (r = 65536 + ((1023 & r) << 10 | 1023 & e.charCodeAt(++s)),
                                    u\[i++\] = 240 | r >> 18,
                                    u\[i++\] = 128 | r >> 12 & 63),
                                    u\[i++\] = 128 | r >> 6 & 63),
                                    u\[i++\] = 128 | 63 & r);
                        else
                            for (i = this.start; s < o && i < 64; ++s)
                                (r \= e.charCodeAt(s)) < 128 ? a\[i >> 2\] |= r << SHIFT\[3 & i++\] : (r < 2048 ? a\[i >> 2\] |= (192 | r >> 6) << SHIFT\[3 & i++\] : (r < 55296 || 57344 <= r ? a\[i >> 2\] |= (224 | r >> 12) << SHIFT\[3 & i++\] : (r = 65536 + ((1023 & r) << 10 | 1023 & e.charCodeAt(++s)),
                                    a\[i \>> 2\] |= (240 | r >> 18) << SHIFT\[3 & i++\],
                                    a\[i \>> 2\] |= (128 | r >> 12 & 63) << SHIFT\[3 & i++\]),
                                    a\[i \>> 2\] |= (128 | r >> 6 & 63) << SHIFT\[3 & i++\]),
                                    a\[i \>> 2\] |= (128 | 63 & r) << SHIFT\[3 & i++\]);
                        this.lastByteIndex \= i,
                            this.bytes += i - this.start,
                            64 <= i ? (this.start = i - 64,
                                this.hash(),
                                this.hashed \= !0) : this.start = i
                    }
                    return 4294967295 < this.bytes && (this.hBytes += this.bytes / 4294967296 << 0,
                        this.bytes \= this.bytes % 4294967296),
                        this
                }
            }
                ,
                Md5.prototype.finalize \= function () {
                    var e, t;
                    this.finalized || (this.finalized = !0,
                        (e \= this.blocks)\[(t = this.lastByteIndex) >> 2\] |= EXTRA\[3 & t\],
                    56 <= t && (this.hashed || this.hash(),
                        e\[0\] \= e\[16\],
                        e\[16\] = e\[1\] = e\[2\] = e\[3\] = e\[4\] = e\[5\] = e\[6\] = e\[7\] = e\[8\] = e\[9\] = e\[10\] = e\[11\] = e\[12\] = e\[13\] = e\[14\] = e\[15\] = 0),
                        e\[14\] = this.bytes << 3,
                        e\[15\] = this.hBytes << 3 | this.bytes >>> 29,
                        this.hash())
                }
                ,
                Md5.prototype.hash \= function () {
                    var e, t, n, r, i, s \= this.blocks,
                        o \= this.first ? ((o = ((e = ((e = s\[0\] - 680876937) << 7 | e >>> 25) - 271733879 << 0) ^ (t = ((t = (-271733879 ^ (n = ((n = (-1732584194 ^ 2004318071 & e) + s\[1\] - 117830708) << 12 | n >>> 20) + e << 0) & (-271733879 ^ e)) + s\[2\] - 1126478375) << 17 | t >>> 15) + n << 0) & (n ^ e)) + s\[3\] - 1316259209) << 22 | o >>> 10) + t << 0 : (e = this.h0,
                            o \= this.h1,
                            t \= this.h2,
                        ((o += ((e = ((e += ((n = this.h3) ^ o & (t ^ n)) + s\[0\] - 680876936) << 7 | e >>> 25) + o << 0) ^ (t = ((t += (o ^ (n = ((n += (t ^ e & (o ^ t)) + s\[1\] - 389564586) << 12 | n >>> 20) + e << 0) & (e ^ o)) + s\[2\] + 606105819) << 17 | t >>> 15) + n << 0) & (n ^ e)) + s\[3\] - 1044525330) << 22 | o >>> 10) + t << 0);
                    o \= ((o += ((e = ((e += (n ^ o & (t ^ n)) + s\[4\] - 176418897) << 7 | e >>> 25) + o << 0) ^ (t = ((t += (o ^ (n = ((n += (t ^ e & (o ^ t)) + s\[5\] + 1200080426) << 12 | n >>> 20) + e << 0) & (e ^ o)) + s\[6\] - 1473231341) << 17 | t >>> 15) + n << 0) & (n ^ e)) + s\[7\] - 45705983) << 22 | o >>> 10) + t << 0,
                        o \= ((o += ((e = ((e += (n ^ o & (t ^ n)) + s\[8\] + 1770035416) << 7 | e >>> 25) + o << 0) ^ (t = ((t += (o ^ (n = ((n += (t ^ e & (o ^ t)) + s\[9\] - 1958414417) << 12 | n >>> 20) + e << 0) & (e ^ o)) + s\[10\] - 42063) << 17 | t >>> 15) + n << 0) & (n ^ e)) + s\[11\] - 1990404162) << 22 | o >>> 10) + t << 0,
                        o \= ((o += ((e = ((e += (n ^ o & (t ^ n)) + s\[12\] + 1804603682) << 7 | e >>> 25) + o << 0) ^ (t = ((t += (o ^ (n = ((n += (t ^ e & (o ^ t)) + s\[13\] - 40341101) << 12 | n >>> 20) + e << 0) & (e ^ o)) + s\[14\] - 1502002290) << 17 | t >>> 15) + n << 0) & (n ^ e)) + s\[15\] + 1236535329) << 22 | o >>> 10) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ t & ((e = ((e += (t ^ n & (o ^ t)) + s\[1\] - 165796510) << 5 | e >>> 27) + o << 0) ^ o)) + s\[6\] - 1069501632) << 9 | n >>> 23) + e << 0) ^ e & ((t = ((t += (e ^ o & (n ^ e)) + s\[11\] + 643717713) << 14 | t >>> 18) + n << 0) ^ n)) + s\[0\] - 373897302) << 20 | o >>> 12) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ t & ((e = ((e += (t ^ n & (o ^ t)) + s\[5\] - 701558691) << 5 | e >>> 27) + o << 0) ^ o)) + s\[10\] + 38016083) << 9 | n >>> 23) + e << 0) ^ e & ((t = ((t += (e ^ o & (n ^ e)) + s\[15\] - 660478335) << 14 | t >>> 18) + n << 0) ^ n)) + s\[4\] - 405537848) << 20 | o >>> 12) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ t & ((e = ((e += (t ^ n & (o ^ t)) + s\[9\] + 568446438) << 5 | e >>> 27) + o << 0) ^ o)) + s\[14\] - 1019803690) << 9 | n >>> 23) + e << 0) ^ e & ((t = ((t += (e ^ o & (n ^ e)) + s\[3\] - 187363961) << 14 | t >>> 18) + n << 0) ^ n)) + s\[8\] + 1163531501) << 20 | o >>> 12) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ t & ((e = ((e += (t ^ n & (o ^ t)) + s\[13\] - 1444681467) << 5 | e >>> 27) + o << 0) ^ o)) + s\[2\] - 51403784) << 9 | n >>> 23) + e << 0) ^ e & ((t = ((t += (e ^ o & (n ^ e)) + s\[7\] + 1735328473) << 14 | t >>> 18) + n << 0) ^ n)) + s\[12\] - 1926607734) << 20 | o >>> 12) + t << 0,
                        o \= ((o += ((i = (n = ((n += ((r = o ^ t) ^ (e = ((e += (r ^ n) + s\[5\] - 378558) << 4 | e >>> 28) + o << 0)) + s\[8\] - 2022574463) << 11 | n >>> 21) + e << 0) ^ e) ^ (t = ((t += (i ^ o) + s\[11\] + 1839030562) << 16 | t >>> 16) + n << 0)) + s\[14\] - 35309556) << 23 | o >>> 9) + t << 0,
                        o \= ((o += ((i = (n = ((n += ((r = o ^ t) ^ (e = ((e += (r ^ n) + s\[1\] - 1530992060) << 4 | e >>> 28) + o << 0)) + s\[4\] + 1272893353) << 11 | n >>> 21) + e << 0) ^ e) ^ (t = ((t += (i ^ o) + s\[7\] - 155497632) << 16 | t >>> 16) + n << 0)) + s\[10\] - 1094730640) << 23 | o >>> 9) + t << 0,
                        o \= ((o += ((i = (n = ((n += ((r = o ^ t) ^ (e = ((e += (r ^ n) + s\[13\] + 681279174) << 4 | e >>> 28) + o << 0)) + s\[0\] - 358537222) << 11 | n >>> 21) + e << 0) ^ e) ^ (t = ((t += (i ^ o) + s\[3\] - 722521979) << 16 | t >>> 16) + n << 0)) + s\[6\] + 76029189) << 23 | o >>> 9) + t << 0,
                        o \= ((o += ((i = (n = ((n += ((r = o ^ t) ^ (e = ((e += (r ^ n) + s\[9\] - 640364487) << 4 | e >>> 28) + o << 0)) + s\[12\] - 421815835) << 11 | n >>> 21) + e << 0) ^ e) ^ (t = ((t += (i ^ o) + s\[15\] + 530742520) << 16 | t >>> 16) + n << 0)) + s\[2\] - 995338651) << 23 | o >>> 9) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ ((e = ((e += (t ^ (o | ~n)) + s\[0\] - 198630844) << 6 | e >>> 26) + o << 0) | ~t)) + s\[7\] + 1126891415) << 10 | n >>> 22) + e << 0) ^ ((t = ((t += (e ^ (n | ~o)) + s\[14\] - 1416354905) << 15 | t >>> 17) + n << 0) | ~e)) + s\[5\] - 57434055) << 21 | o >>> 11) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ ((e = ((e += (t ^ (o | ~n)) + s\[12\] + 1700485571) << 6 | e >>> 26) + o << 0) | ~t)) + s\[3\] - 1894986606) << 10 | n >>> 22) + e << 0) ^ ((t = ((t += (e ^ (n | ~o)) + s\[10\] - 1051523) << 15 | t >>> 17) + n << 0) | ~e)) + s\[1\] - 2054922799) << 21 | o >>> 11) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ ((e = ((e += (t ^ (o | ~n)) + s\[8\] + 1873313359) << 6 | e >>> 26) + o << 0) | ~t)) + s\[15\] - 30611744) << 10 | n >>> 22) + e << 0) ^ ((t = ((t += (e ^ (n | ~o)) + s\[6\] - 1560198380) << 15 | t >>> 17) + n << 0) | ~e)) + s\[13\] + 1309151649) << 21 | o >>> 11) + t << 0,
                        o \= ((o += ((n = ((n += (o ^ ((e = ((e += (t ^ (o | ~n)) + s\[4\] - 145523070) << 6 | e >>> 26) + o << 0) | ~t)) + s\[11\] - 1120210379) << 10 | n >>> 22) + e << 0) ^ ((t = ((t += (e ^ (n | ~o)) + s\[2\] + 718787259) << 15 | t >>> 17) + n << 0) | ~e)) + s\[9\] - 343485551) << 21 | o >>> 11) + t << 0,
                        this.first ? (this.h0 \= e + 1732584193 << 0,
                            this.h1 \= o - 271733879 << 0,
                            this.h2 \= t - 1732584194 << 0,
                            this.h3 \= n + 271733878 << 0,
                            this.first \= !1) : (this.h0 = this.h0 + e << 0,
                            this.h1 \= this.h1 + o << 0,
                            this.h2 \= this.h2 + t << 0,
                            this.h3 \= this.h3 + n << 0)
                }
                ,
                Md5.prototype.hex \= function () {
                    this.finalize();
                    var e \= this.h0
                        , t \= this.h1
                        , n \= this.h2
                        , r \= this.h3;
                    return HEX\_CHARS\[e >> 4 & 15\] + HEX\_CHARS\[15 & e\] + HEX\_CHARS\[e >> 12 & 15\] + HEX\_CHARS\[e >> 8 & 15\] + HEX\_CHARS\[e >> 20 & 15\] + HEX\_CHARS\[e >> 16 & 15\] + HEX\_CHARS\[e >> 28 & 15\] + HEX\_CHARS\[e >> 24 & 15\] + HEX\_CHARS\[t >> 4 & 15\] + HEX\_CHARS\[15 & t\] + HEX\_CHARS\[t >> 12 & 15\] + HEX\_CHARS\[t >> 8 & 15\] + HEX\_CHARS\[t >> 20 & 15\] + HEX\_CHARS\[t >> 16 & 15\] + HEX\_CHARS\[t >> 28 & 15\] + HEX\_CHARS\[t >> 24 & 15\] + HEX\_CHARS\[n >> 4 & 15\] + HEX\_CHARS\[15 & n\] + HEX\_CHARS\[n >> 12 & 15\] + HEX\_CHARS\[n >> 8 & 15\] + HEX\_CHARS\[n >> 20 & 15\] + HEX\_CHARS\[n >> 16 & 15\] + HEX\_CHARS\[n >> 28 & 15\] + HEX\_CHARS\[n >> 24 & 15\] + HEX\_CHARS\[r >> 4 & 15\] + HEX\_CHARS\[15 & r\] + HEX\_CHARS\[r >> 12 & 15\] + HEX\_CHARS\[r >> 8 & 15\] + HEX\_CHARS\[r >> 20 & 15\] + HEX\_CHARS\[r >> 16 & 15\] + HEX\_CHARS\[r >> 28 & 15\] + HEX\_CHARS\[r >> 24 & 15\]
                }
                ,
                Md5.prototype.toString \= Md5.prototype.hex,
                Md5.prototype.digest \= function () {
                    this.finalize();
                    var e \= this.h0
                        , t \= this.h1
                        , n \= this.h2
                        , r \= this.h3;
                    return \[255 & e, e >> 8 & 255, e >> 16 & 255, e >> 24 & 255, 255 & t, t >> 8 & 255, t >> 16 & 255, t >> 24 & 255, 255 & n, n >> 8 & 255, n >> 16 & 255, n >> 24 & 255, 255 & r, r >> 8 & 255, r >> 16 & 255, r >> 24 & 255\]
                }
                ,
                Md5.prototype.array \= Md5.prototype.digest,
                Md5.prototype.arrayBuffer \= function () {
                    this.finalize();
                    var e \= new ArrayBuffer(16)
                        , t \= new Uint32Array(e);
                    return t\[0\] = this.h0,
                        t\[1\] = this.h1,
                        t\[2\] = this.h2,
                        t\[3\] = this.h3,
                        e
                }
                ,
                Md5.prototype.buffer \= Md5.prototype.arrayBuffer,
                Md5.prototype.base64 \= function () {
                    for (var e, t, n, r = "", i = this.array(), s = 0; s < 15;)
                        e \= i\[s++\],
                            t \= i\[s++\],
                            n \= i\[s++\],
                            r += BASE64\_ENCODE\_CHAR\[e >>> 2\] + BASE64\_ENCODE\_CHAR\[63 & (e << 4 | t >>> 4)\] + BASE64\_ENCODE\_CHAR\[63 & (t << 2 | n >>> 6)\] + BASE64\_ENCODE\_CHAR\[63 & n\];
                    return e = i\[s\],
                    r \+ (BASE64\_ENCODE\_CHAR\[e >>> 2\] + BASE64\_ENCODE\_CHAR\[e << 4 & 63\] + "\==")
                }
            ;
            var exports \= createMethod();
            COMMON\_JS ? module.exports \= exports : root.md5 = exports
        }()
    }
))
    , secret \= "0b50b02fd0d73a9c4c8c3a781c30845f";

function createSign(e) {
    if ("\[object Object\]" !== Object.prototype.toString.call(e))
        throw new Error("The parameter of query must be a Object.");
    var t \= Math.floor(Date.now() / 1e3);
    Object.assign(e, {
        timestamp: t
    });
    var n \= Object.keys(e);
    n.sort();
    for (var r = "", i = 0; i < n.length; i++) {
        var s \= n\[i\];
        r += (0 == i ? "" : "&") + s + "\=" + e\[s\]
    }
    return {
        sign: md5(r += secret),
        timestamp: t,
        md5: md5
    }
}

e \= {
    "TSID": "T10049736422",
    "appid": 16073360
}
console.log(createSign(e))

Python实现代码💥

import pprint
import requests
import execjs
import time
date\_time \= int(time.time())
f \= open('demo.js', encoding='utf-8').read()
js\_code \= execjs.compile(f)
link\_e \= {
    "word": "许嵩",
    "type": 1,
    "pageNo": 3,
    "pageSize": 20,
    "appid": 16073360,
    "timestamp": date\_time
}
link\_sign \= js\_code.call('createSign', link\_e)
print(link\_sign)
link \= f'https://music.91q.com/v1/search?sign={link\_sign\["sign"\]}&word=%E8%AE%B8%E5%B5%A9&type=1&pageNo=3&pageSize=20&appid=16073360&timestamp={date\_time}'
headers \= {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
}
response \= requests.get(url=link, headers=headers)
for index in response.json()\['data'\]\['typeTrack'\]:
    TSID \= index\['TSID'\]
    e \= {
        "TSID": TSID,
        "appid": 16073360,
        "timestamp": date\_time
    }
    sign \= js\_code.call('createSign', e)\['sign'\]
    url \= f'https://music.91q.com/v1/song/tracklink?sign={sign}&appid=16073360&TSID={TSID}&timestamp={date\_time}'
    json\_data \= requests.get(url=url, headers=headers).json()
    pprint.pprint(json\_data)
    break


歌曲列表获取音乐ID同样也有一个sign加密参数, 加密方式是一样的, 改一下传入的参数就可以了


最后这里免费分享给大家一份Python全台学习资料,包含视频、源码。课件,希望能帮到那些不满现状,想提升自己却又没有方向的朋友,也可以和我一起来学习交流呀。
编程资料、学习路线图、源代码、软件安装包【点击这里】领取!

Python所有方向的学习路线图,清楚各个方向要学什么东西
100多节Python课程视频,涵盖必备基础、爬虫和数据分析
100多个Python实战案例,学习不再是只会理论
华为出品独家Python漫画教程,手机也能学习
历年互联网企业Python面试真题,复习时非常方便
请添加图片描述

请添加图片描述

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、全套PDF电子书

书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

请添加图片描述

四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值