Python 偷偷爬取QQ音樂全部歌曲,這聽起來就不錯

来源:https://www.cnblogs.com/123456feng/archive/2022/04/13/16137845.html
-Advertisement-
Play Games

前景介紹## 標題 最近小伙伴們聽歌的興趣大漲,網抑雲綜合症已經遍佈各地。 咱們再來抬高一波QQ音樂的熱度吧。 爬它! 目標:歌手列表 任務:將A到Z的歌手以及全部頁數的歌存到本地和資料庫 觀察網頁url結構 當我們進入網頁時發現此時是一個無參數的html網頁載入。 尋找我們想要拿到的位置尋找變化, ...


前景介紹## 標題

最近小伙伴們聽歌的興趣大漲,網抑雲綜合症已經遍佈各地。

咱們再來抬高一波QQ音樂的熱度吧。

爬它!

目標:歌手列表

在這裡插入圖片描述

任務:將A到Z的歌手以及全部頁數的歌存到本地和資料庫

觀察網頁url結構

當我們進入網頁時發現此時是一個無參數的html網頁載入。
在這裡插入圖片描述

尋找我們想要拿到的位置尋找變化,但我們點擊A開頭的網頁跳轉時,發現 url 改變了,index 參數應該是首字母,page 參數應該

是頁數變化。
在這裡插入圖片描述

這樣的話就減少一個找參數的時間啦。

找到XML

還是習慣的點開檢查按鍵,找到首字母的作者提供的XML都需要什麼參數,隨便點點A-Z發現 XML 有一個請求蹦出來,裡面返回

了是個 json 數據集,都點開看看發現找到了每個作者的參數了。成功了一小半!

在這裡插入圖片描述

既然拿到了XML的網站,POST請求是一定的啦,接下來就該分析分析網站所需要的參數都是什麼了,大致猜測一下,這麼多數

據中sign和data參數有點詭異,不像是正常的參數,加密參數也找到了。

在這裡插入圖片描述

破解sign加密參數

search 找一下sign都在哪裡。因為sign應該是個變數,所以說在他後面加個=會查找的更精確一些。找到一個sign參數的位置,這

應該是個JavaScript代碼,那就應該是這裡面了。點進去!
在這裡插入圖片描述

在JavaScript中找到了 sign 的位置,找到了一個JavaScript調用的網站,我們進去看看是什麼代碼在裡面。
在這裡插入圖片描述

當我們進入網站之後,代碼有點亂我們線上格式化一下看看裡面是什麼。
在這裡插入圖片描述

格式化代碼後發現這個裡面含有sign參數。這個應該是sign的加密演算法,但是其中傳了一個參數進入,我們需要瞭解一下他傳了什

麽參數,這樣我們的sign就出來了。
在這裡插入圖片描述

回到我們調用JavaScript網站的文件中,繼續往下看,我們發現 sign 傳數值就在他的下部。我們看到了傳了個data給這個sign加

密函數,點斷點看看data參數是什麼。這data值看的好眼熟,這不是一開始很奇怪那個參數data麽。原來data弄出來了sign就能給

出來的。
在這裡插入圖片描述

我們繼續找剛纔的sign。點擊下一次跳轉我們發現我們找到另一個函數在裡面,產生了一種疑惑,這個函數是做什麼的,他為什

麽會跳向這裡。在這裡插入圖片描述

那我們先看看我們格式化出來的JavaScript到底能不能運行吧。說不定能運行呢。
在這裡插入圖片描述

哦吼,能運行,那就好辦了,看看他返回的參數到底是啥,在開頭定義一個sign=null,將t返回給sign,再把sign列印出來。這是

剛纔的那個跳轉過去的方法。
在這裡插入圖片描述

原來如此,那我們將sign調用一下加個(),我們就能發現sign的值就出現了。但我們重覆運行發現我們無法得到他的加密值,因為

這些都是一樣的。
在這裡插入圖片描述

回想我們剛纔說的話,他需要加一個data參數才可以獲得加密參數,那好再改一下。
在這裡插入圖片描述

首先我們先下載一個python調用JavaScript的庫。pip install PyExecJS

開始寫python代碼

Python學習交流Q群:906715085###
import execjs

def get_sign(data):    
with open('a.js','r',encoding='utf-8')
 as f:      
  text = f.read()   
   js_data = execjs.compile(text)    
   sign = js_data.call('get_sign',data)    
   return sign  
    
    if __name__ == "__main__":    
   data = '{"comm":{"ct":24,"cv":0},"singerList":{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":2,"sin":0,"cur_page":1}}}'    
   sign = get_sign(data)    
   print(data)    
   print(sign)

 

這是多次調用代碼的結果,發現data傳入成功了。

在這裡插入圖片描述

獲取歌手個數以及頁數

個數其實一開始我們已經拿到了,只不過那時候沒介紹,仔細的童鞋們應該是看到了總數到底為多少個。我們點開剛纔的返回

json結果就能看到total已經給出來當前的個數了。
在這裡插入圖片描述

現在該分析一下data參數,盲猜一通估計page和index都在data裡面,要不然這個參數傳不上去呀。好的分析一下data到底有啥,

咱拿過來看看。data裡面看到了get_singer_list這個應該是主要的東西。

#這個是 A開頭 第一頁
#{"comm":{"ct":24,"cv":0},"singerList":
{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":1,"sin":0,"cur_page":1}}}
#這個是 B開頭 第一頁
#{"comm":{"ct":24,"cv":0},"singerList":
{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":2,"sin":0,"cur_page":1}}}
#這個是 B開頭 第二頁
#{"comm":{"ct":24,"cv":0},"singerList":
{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":2,"sin":80,"cur_page":2}}}
#這個是 B開頭 第三頁
#{"comm":{"ct":24,"cv":0},"singerList":
{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":2,"sin":160,"cur_page":3}}}

 

大致我們能分析出來。

•字母的變化在 index 處,也就是A到Z以及後面的# 應該是一共27個在裡面,也就是index從1到27我們需要傳給他。

•頁數的變化在 sin 這裡,第一頁是0,第二頁就是80,第三頁是160,冷靜分析一下應該是從0開始以80為公差的等差數列。這個

八十應該是代表每一頁都含有八十個歌手。

•cur_page應該就是當前頁數的意思。那咱們跟著sin一起改變。

那在這我們拿到了總數,加上每一頁總共能展示多少,因為多出來的個數需要占一頁才可以,我們使用向下取整。

在這裡插入圖片描述

獲取作者名字以及id號

我們根據上述寫出來爬蟲代碼後,就可以成功獲取 json 的返回值了,在裡面我們能看到一個歌手的參數一共有五個,其中

singer_mid 和 singer_name 是我們所需要的。拿到這兩個值後可以進入網站下載當前歌手的歌曲。
在這裡插入圖片描述

尋找歌手的歌曲

我們隨意點進去一個歌手,進去後尋找XML的網站,我在這裡找好了是 getSingerSong 變數。

在這裡能獲取歌手的每首歌的所能拿到的結果。
在這裡插入圖片描述

我們看一下裡面都需要什麼參數,好像和上次的差不多哦。sign已經獲取到了,data是給定的變數。單純的data有點變化,但問

題不大。那說明還是能正常訪問這個XML的。

data中有點變化的位置就是 singerMid ,這個參數我們在剛纔已經獲取到了。直接在裡面引用一下就好了。begin的參數是一個歌

手歌的頁數,num是一頁中包括多少歌曲。其實我們傳參數可以將這個參數改一下的。把num的值改到一個很大的值,我們就可

以不需要改變begin的參數就能拿到所有的歌曲結果。
在這裡插入圖片描述

我們仔細找一下 json 裡面的參數,點擊音樂鏈接進入發現是https://y.qq.com/n/yqq/song/002MQlds19S8qy.html,我們能發現,

在這個歌曲裡面的 mid 參數就是每首歌的格式化位置。
在這裡插入圖片描述

尋找下載歌曲的m4a鏈接

我們點入播放中。尋找裡面的m4a鏈接看看都包含什麼參數,發現存在七個鏈接都是。但我們仔細一看歌曲的大小我們就會發

現,前幾個都是有問題的發包,一首歌怎麼可能只有幾kb呢。毫不猶豫點進去最後一個。
在這裡插入圖片描述

哦吼,這回參數不一樣了哦。那我們在重新分析一下下吧別懶了。
在這裡插入圖片描述

我們先查找一下他給出來的一些包,看看能不能找到一個非加密參數出來。

果然,功夫不負有心人。vkey 就不是個加密參數!

在這裡插入圖片描述

破解參數前先學會"投機取巧"

我不知道剛纔有沒有仔細看這個位置,發現這個也是個很長的字元串,但是他很特殊,特殊到它和m4a的url是一樣的。
在這裡插入圖片描述

為了讓你們看到,我在這裡把這倆寫出來,發現到他們差了什麼。不變的字元串首碼。。

#C400002wiewH40saXM.m4a?guid=9232644380&vkey=A6F8B706468C0ECFE0F8B6E5E8AAD783D5F852ED0CA66692EB1033B209080BE61208609BEBC2EAF66FA86AC887C8C9F03C02A152E2EF4E24&uin=0&fromtag=66
# https://isure.stream.qqmusic.qq.com/C400002wiewH40saXM.m4a?guid=9232644380&vkey=A6F8B706468C0ECFE0F8B6E5E8AAD783D5F852ED0CA66692EB1033B209080BE61208609BEBC2EAF66FA86AC887C8C9F03C02A152E2EF4E24

 

那我們先看看vkey到底需要什麼參數給進去。其他參數還是都那些,還是差了一個data需要給進去的。咱們分析一下data都需要

給啥吧。

在這裡插入圖片描述

#{"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"9232644380","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"9232644380","songmid":["002MQlds19S8qy"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":24,"cv":0}}

 

大致分析了一下

•guid是個無用參數。

•songmid 是歌曲的 mid,我們剛纔已經獲取了

•uin 需要加入一個qq號才可以獲取,如果未登陸預設為0

•其他都是定死的參數

m4a文件是一個二進位文件。所以說我們寫代碼一定要寫入二進位文件才可以。

代碼優化

1.因為數據量過大,日常存入資料庫

2.因為數據下載量大,使用多進程爬取。將A-Z及#各開一個進程

3.防止存入資料庫在多線程階段同時占用,上鎖

全部代碼

crawl.py

 

db.py

Python交流Q群:906715085###
#Python3.7 
#encoding = utf-8
import execjs,requests,math,os,threading
from urllib import parse
from concurrent.futures
import ThreadPoolExecutor,ProcessPoolExecutor
from db import SQLsession,Song
lock = threading.Lock()
headers = {   
 'User-Agent':'Mozilla/5.0 (Macintosh; 
 Intel Mac OS X 10_14_2) 
 AppleWebKit/537.36 (KHTML, like Gecko) 
 Chrome/85.0.4183.102 Safari/537.36',  
 'Referer':'https://y.qq.com/portal/singer_list.html',
 }
 session = SQLsession()
 def get_sign(data):   
with open('./QQ音樂/get_sign.js','r',encoding='utf-8') as
 f:        
  text = f.read()    
  js_data = execjs.compile(text)    
  sign = js_data.call('get_sign',data)    
  return sign
  def myProcess():   
   #把歌手按照首字母分為27類   
    with ProcessPoolExecutor(max_workers
     = 2) as p:#創建27個進程        
    for i in range(1,28):            
    p.submit(get_singer_mid,i)def get_singer_mid(index):   
     #index =  1-----27    #打開歌手列表頁面,找出singerList,找出所有歌手的數目,除於80,構造後續頁面獲取page歌手    #找出mid, 用於歌手詳情頁    
 data = '{"comm":{"ct":24,"cv":0},"singerList":'\        
 '{"module":"Music.SingerListServer","method":"get_singer_list","param":'\        '{"area":-100,"sex":-100,"genre":-100,"index":%s,"sin":0,"cur_page":1}}}'%(str(index))    
 sign = get_sign(data)    url = 'https://u.y.qq.com/cgi-bin/musics.fcg?-=getUCGI6720748185279282&g_tk=5381'\       
  '&sign={}'\       
   '&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8'\        '&notice=0&platform=yqq.json&needNewCode=0'\       
 '&data={}'.format(sign,parse.quote(data))    

 html = requests.get(url,headers = headers).json()    
 total = html['singerList']['data']['total']#多少個歌手    
 pages = int(math.floor(int(total)/80))#向下取整    thread_number = pages    
 Thread = ThreadPoolExecutor(max_workers = thread_number)    sin = 0    #分頁迭代每一個字母下的所有頁面歌手    for page in range(1,pages+2):        
 data = '{"comm":{"ct":24,"cv":0},"singerList":{"module":"Music.SingerListServer","method":"get_singer_list","param":{"area":-100,"sex":-100,"genre":-100,"index":%s,"sin":%s,"cur_page":%s}}}'%(str(index),str(sin),str(page))        
 sign = get_sign(data)       
  url = 'https://u.y.qq.com/cgi-bin/musics.fcg?-=getUCGI6720748185279282&g_tk=5381'\            
  '&sign={}'\           
   '&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8'\            '&notice=0&platform=yqq.json&needNewCode=0'\           
   '&data={}'.format(sign,parse.quote(data))         
   html = requests.get(url,headers = headers).json()        
   sings = html['singerList']['data']['singerlist']        
   for sing in sings:           
    singer_name = sing['singer_name']   #獲取歌手名字           
     mid = sing['singer_mid']           
      #獲取歌手mid            
     Thread.submit(get_singer_data,mid = mid,                            
     singer_name = singer_name,)        
     sin+=80#獲取歌手信息def get_singer_data(mid,singer_name):    
     #獲取歌手mid,進入歌手詳情頁,也就是每一個歌手歌曲所在頁面    
     #找出歌手的歌曲信息頁    
     data = '{"comm":{"ct":24,"cv":0},"singerSongList":{"method":"GetSingerSongList","param":'\            '{"order":1,"singerMid":"%s","begin":0,"num":10}'\            
     ',"module":"musichall.song_list_server"}}'%(str(mid))    
     sign = get_sign(data)   
      url = 'https://u.y.qq.com/cgi-bin/musics.fcg?-=getSingerSong4707786209273719'\        
      '&g_tk=5381&sign={}&loginUin=0'\       
       '&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0'\       
        '&data={}'.format(sign,parse.quote(data))    
        html = requests.get(url,headers = headers).json()    
        songs_num = html['singerSongList']['data']['totalNum']   
         for number in range(0,songs_num,100):       
          data = '{"comm":{"ct":24,"cv":0},"singerSongList":{"method":"GetSingerSongList","param":'\            '{"order":1,"singerMid":"%s","begin":%s,"num":%s}'\           
           ',"module":"musichall.song_list_server"}}'%(str(mid),str(number),str(songs_num))        
           sign = get_sign(data)       
            url = 'https://u.y.qq.com/cgi-bin/musics.fcg?-=getSingerSong4707786209273719'\           
             '&g_tk=5381&sign={}&loginUin=0'\           
              '&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0'\            '&data={}'.format(sign,parse.quote(data))        
 html = requests.get(url,headers = headers).json()       
  datas = html['singerSongList']['data']['songList']       
   for d in datas:            sing_name = d['songInfo']['title']            
   song_mid = d['songInfo']['mid']            try:               
    lock.acquire()               
     session.add(Song(song_name = sing_name,                               
     song_singer = singer_name,                                
     song_mid = song_mid))               
      session.commit()                
      lock.release()                
      print('commit')           
 except:                                      
  session.rollback()                
  print('rollbeak')           
  print('歌手名字:{}\t歌曲名字:{}\t歌曲ID:{}'.format(singer_name,sing_name,song_mid))            download(song_mid,sing_name,singer_name)def download(song_mid,sing_name,singer_name):    
  qq_number = '請在這裡寫你的qq號'    try:qq_number = str(int(qq_number))    
  except:raise 'qq號未填寫'   
   data = '{"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch"'\       
    ',"param":{"guid":"4803422090","calltype":0,"userip":""}},'\        
    '"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey",'\       
     '"param":{"guid":"4803422090","songmid":["%s"],"songtype":[0],'\       
      '"uin":"%s","loginflag":1,"platform":"20"}},"comm":{"uin":%s,"format":"json","ct":24,"cv":0}}'%(str(song_mid),str(qq_number),str(qq_number))    
 sign = get_sign(data)        
 url = 'https://u.y.qq.com/cgi-bin/musics.fcg?-=getplaysongvkey27494207511290925'\        
 '&g_tk=1291538537&sign={}&loginUin={}'\        
 '&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0'\        
 '&platform=yqq.json&needNewCode=0&data={}'.format(sign,qq_number,parse.quote(data))    
 html = requests.get(url,headers = headers).json()   
  try:        
  purl = html['req_0']['data']['midurlinfo'][0]['purl']        
  url = 'http://119.147.228.27/amobile.music.tc.qq.com/{}'.format(purl)       
   html = requests.get(url,headers = headers)        
   html.encoding = 'utf-8'        
   sing_file_name = '{} -- {}'.format(sing_name,singer_name)       
    filename = './QQ音樂/歌曲'       
     if not os.path.exists(filename):            
    os.makedirs(filename)        
    with open('./QQ音樂/歌曲/{}.m4a'.format(sing_file_name),'wb') as f:            
    print('\n正在下載{}歌曲.....\n'.format(sing_file_name))            
    f.write(html.content)     
    except:        
    print('查詢許可權失敗,或沒有查到對應的歌曲')if __name__ == "__main__":    
    myProcess()

 

from sqlalchemy import

Column,Integer,String,create_engine
from sqlalchemy.orm import 
 sessionmaker,scoped_session
 from sqlalchemy.ext.
 declarative import declarative_base
 #此處沒有使用pymysql的驅動
 #請安裝pip install mysql-connector-python
 #engine中的 mysqlconnector 為 mysql官網驅動engine = create_engine
 ('mysql+mysqlconnector://root:root@localhost:3306/test?charset=utf8',                   
 max_overflow = 500,#超過連接池大小外最多可以創建的鏈接                   
 pool_size = 100,#連接池大小                   
 echo = False,#調試信息展示      
 )Base = declarative_base()class Song(Base):    __
 tablename__ = 'song'    
 song_id = Column(Integer,primary_key = True,autoincrement = True)    
 song_name = Column(String(64))    
 song_ablum = Column(String(64))    
 song_mid = Column(String(50))    
 song_singer = Column(String(50))Base.metadata.create_all(engine)DBsession = sessionmaker(bind = engine)SQLsession = scoped_session(DBsession)

 

get_sign.js

this.window = this;
var sign = null;
!function(n, t) {   
 "object" == typeof exports && "undefined" != typeof module ? module.exports = t() :
  "function" == typeof 
  define && define.amd ? define(t) : (n = n || self).
 getSecuritySign = t()
 }
  (this,function() 
 {    
 "use strict";   
 var n = function() {       
  if ("undefined" != typeof self) return self;        
  if ("undefined" != typeof window) return window;        
  if ("undefined" != typeof global) return global;       
   throw new Error("unable to locate global object")   
    } ();   
     n.__sign_hash_20200305 = function(n) {       
      function l(n, t) {           
       var o = (65535 & n) + (65535 & t);           
        return (n >> 16) + (t >> 16) + (o >> 16) << 16 | 65535 & o      
          }       
 function r(n, t, o, e, u, p) {            
 return l((i = l(l(t, n), l(e, p))) << (r = u) | i >>> 32 - r, o);           
  var i, r      
    }        
    function g(n, t, o, e, u, p, i) {            
    return r(t & o | ~t & e, n, t, u, p, i)       
     }        
     function a(n, t, o, e, u, p, i) {           
      return r(t & e | o & ~e, n, t, u, p, i) 
      }       
function s(n, t, o, e, u, p, i) {           
return r(t ^ o ^ e, n, t, u, p, i)       
 }       
  function v(n, t, o, e, u, p, i) {            
  return r(o ^ (t | ~e), n, t, u, p, i)       
   }        
 function t(n) {            
return function(n) {                
var t, o = "";               
 for (t = 0; t < 32 * n.length; t += 8) o += String.fromCharCode(n[t >> 5] >>> t % 32 & 255);                return o            
 } (function(n, t) {               
  n[t >> 5] |= 128 << t % 32,                
  n[14 + (t + 64 >>> 9 << 4)] = t;               
   var o, e, u, p, i, r = 1732584193,               
    f = -271733879,                
    h = -1732584194,                
    c = 271733878;               
     for (o = 0; o < n.length; o += 16) r = g(e = r, u = f, p = h, i = c, n[o], 7, -680876936),                c = g(c, r, f, h, n[o + 1], 12, -389564586),                
     h = g(h, c, r, f, n[o + 2], 17, 606105819),               
      f = g(f, h, c, r, n[o + 3], 22, -1044525330),               
       r = g(r, f, h, c, n[o + 4], 7, -176418897),              
         c = g(c, r, f, h, n[o + 5], 12, 1200080426),               
          h = g(h, c, r, f, n[o + 6], 17, -1473231341),               
           f = g(f, h, c, r, n[o + 7], 22, -45705983),               
            r = g(r, f, h, c, n[o + 8], 7, 1770035416),                           
c = g(c, r, f, h, n[o + 9], 12, -1958414417),                
h = g(h, c, r, f, n[o + 10], 17, -42063),                
f = g(f, h, c, r, n[o + 11], 22, -1990404162),                
r = g(r, f, h, c, n[o + 12], 7, 1804603682),                
c = g(c, r, f, h, n[o + 13], 12, -40341101),                
h = g(h, c, r, f, n[o + 14], 17, -1502002290	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • uni-app詳解 一、介紹 uni-app 是一個使用 Vue.js(opens new window)開發所有前端應用的框架,開發者編寫一套代碼,可發佈到iOS、Android、Web(響應式)、以及各種小程式(微信/支付寶/百度/頭條/飛書/QQ/快手/釘釘/淘寶)、快應用等多個平臺。 uni ...
  • 做的項目中需要將後端提供的數據展示在前端頁面,一開始我是用JS的setInterval()方法,設置一個時間,每過時間發起一次ajax請求。雖然也能湊活著實現,但總感覺數據不是實時刷新的,而且還占用資源,所以學習WebSocke,並總結了一下,以下是本人總結的前後端WebSocke相關代碼: 一、後 ...
  • 命令模式是什麼 命令模式是一種行為型設計模式,它可以將一個請求封裝為一個對象,使發出請求的責任和執行請求的責任分割開。這樣兩者之間通過命令對象進行溝通,這樣方便將命令對象進行儲存、傳遞、調用、增加與管理。 為什麼用命令模式 在軟體開發系統中,“方法的請求者”與“方法的實現者”之間經常存在緊密的耦合關 ...
  • 模板方法模式是什麼 模版方法模式是設計模式中的行為型的一種模式,它在基類中定義了一個演算法的框架,允許子類在不修改結構的情況下重寫演算法的特定步驟。 為什麼要用模板方法模式 模板方法將整個演算法轉換為一系列獨立的步驟,以便子類能對其進行擴展,同時還可讓超類中所定義的結構保持完整。或者當多個類的演算法步驟一致 ...
  • 平時開發 Python 代碼過程中,經常會遇到這個報錯: ValueError: list.remove(x): x not in list 錯誤提示信息也很明確,就是移除的元素不在列表之中。 比如: >>> lst = [1, 2, 3] >>> lst.remove(4) Traceback ( ...
  • Intellij IDEA 2022 正式發佈了,作為正版用戶,胖哥趕緊更新了一波,好家伙!這幾個功能確實很香啊。新版更新的東西真不少,不愧是一個大版本更新。 依賴分析 IDEA的依賴檢查、依賴衝突解決長期為人詬病,現在終於引進了依賴分析器,它可以幫助你對項目中的依賴信息進行檢索,以 幫助您檢測和解 ...
  • 《零基礎學Java》 JDBC中常用的類和介面 利用JDBC的這些類和介面可以更方便地訪問並處理存儲在資料庫中的數據。 DriverManager類 DriverManager類 是JDBC的管理層,用來管理資料庫中的驅動程式。在使用Java操作資料庫之前,必須使用 Class類 的 靜態方法for ...
  • 來源:blog.csdn.net/qq_34886352/article/details/103581973 一、Nginx安裝 1、去官網http://nginx.org/下載對應的nginx包,推薦使用穩定版本 2、上傳nginx到linux系統 3、安裝依賴環境 (1)安裝gcc環境 yum ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...