竟然有人號稱全網最全python正則,學不會去打他!!!

拋磚引玉

一般對於我們爬蟲而言,需要爬取的是某個網站或者某個應用的內容,提取有用的價值。那麼爬取的內容無疑是分爲兩種,非結構化數據與結構化數據
遇到非結構化數據我們如何處理?
:現有數據,再有結構
遇到結構化數據我們又如何處理呢?
:先有結構,再有數據
總結:對不同類型的數據我們應該採用不同的方式進行處理

筆者能不能說一下什麼是非結構化數據,什麼是結構化數據啊?我聽着有點懵!
我應聲答道

結構化數據

結構化數據是指:由二維表結構來邏輯表達和實現的數據,嚴格地遵循數據格式與長度規範,主要通過關係型數據庫進行存儲和管理。也稱作行數據,一般特點是:數據以行爲單位,一行數據表示一個實體的信息,每一行數據的屬性是相同的。
我給你舉個例子把!

姓名 電話 家庭住址
張三 13682645831 安徽
李四 13546286999 濟南
小明 13648971245 山東

總結:這就是典型的結構化數據,也是數據庫常用的表,方便存取,數據一目瞭然,結構已經很清晰了,直接進行取值就可以了。

非結構化數據

非結構化數據是指:數據結構不規則或不完整,沒有預定義的數據模型,不方便用數據庫二維邏輯表來表現的數據。包括所有格式的辦公文檔、文本、圖片、HTML、各類報表、圖像和音頻/視頻信息等等。那麼我們經常跟我們爬蟲打交道的就是HTML,例如如下代碼

<div class="result c-container " id="3" srcid="1599" tpl="se_com_default" data-click="{&quot;rsv_bdr&quot;:&quot;0&quot;,&quot;p5&quot;:3}"><h3 class="t"><a data-click="{
			'F':'778317EA',
			'F1':'9D73F1E4',
			'F2':'4C26DF6A',
			'F3':'54E5263F',
			'T':'1582260877',
						'y':'DD7EBFFF'
												}" href="http://www.baidu.com/link?url=y8YiZbpqtrwQEFdDjfPT15iC_enWhsFXI2YnC_LhE4ixGH1UTKhqZUvxEpmEMEgU" target="_blank"><em>新聞</em>中心首頁_新浪網</a></h3><div class="c-row c-gap-top-small"><div class="general_image_pic c-span6"><a class="c-img6" style="height:75px" href="http://www.baidu.com/link?url=y8YiZbpqtrwQEFdDjfPT15iC_enWhsFXI2YnC_LhE4ixGH1UTKhqZUvxEpmEMEgU" target="_blank"><img class="c-img c-img6" src="https://dss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1731248121,277041329&amp;fm=58&amp;s=0DE6CD13D1A06D015651B0D6000080B1&amp;bpow=121&amp;bpoh=75" style="height:75px;"></a></div><div class="c-span18 c-span-last"><div class="c-abstract">新浪網<em>新聞</em>中心是新浪網最重要的頻道之一,24小時滾動報道國內、國際及社會<em>新聞</em>。每日編髮<em>新聞</em>數以萬計。</div><div class="f13"><a target="_blank" href="http://www.baidu.com/link?url=y8YiZbpqtrwQEFdDjfPT15iC_enWhsFXI2YnC_LhE4ixGH1UTKhqZUvxEpmEMEgU" class="c-showurl" style="text-decoration:none;">news.sina.com.cn/&nbsp;</a><div class="c-tools" id="tools_10917320878357133208_3" data-tools="{&quot;title&quot;:&quot;新聞中心首頁_新浪網&quot;,&quot;url&quot;:&quot;http://www.baidu.com/link?url=y8YiZbpqtrwQEFdDjfPT15iC_enWhsFXI2YnC_LhE4ixGH1UTKhqZUvxEpmEMEgU&quot;}"><a class="c-tip-icon"><i class="c-icon c-icon-triangle-down-g"></i></a></div><span class="c-icons-outer"><span class="c-icons-inner"></span></span>&nbsp;-&nbsp;<a data-click="{'rsv_snapshot':'1'}" href="http://cache.baiducontent.com/c?m=9d78d513d9d437ad4f9c94697c61c0171e40c72362d88a5339968449e079461d1023a2ac2755515f8f966b6776fe1403fdf041236b1e&amp;p=882a9546ccdd5be512b1c7710f5e&amp;newp=882a9546929f15ef0be29627175092695d0fc20e38d6db01298ffe0cc4241a1a1a3aecbf22291601d1cf786c0aaa4f56eaf133723d0034f1f689df08d2ecce7e6bd47374&amp;user=baidu&amp;fm=sc&amp;query=%D0%C2%CE%C5&amp;qid=a94b7c1a002530dd&amp;p1=3" target="_blank" class="m">百度快照</a><span class="c-pingjia">&nbsp;-&nbsp;<a href="https://www.baidu.com/tools?url=http%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3Dy8YiZbpqtrwQEFdDjfPT15iC_enWhsFXI2YnC_LhE4ixGH1UTKhqZUvxEpmEMEgU&amp;jump=https%3A%2F%2Fkoubei.baidu.com%2Fp%2Fsentry%3Ftitle%3D%02%E6%96%B0%E9%97%BB%03%E4%B8%AD%E5%BF%83%01%E9%A6%96%E9%A1%B5%01_%01%E6%96%B0%E6%B5%AA%01%E7%BD%91%01%26q%3D%E6%96%B0%E9%97%BB%26from%3Dps_pc4&amp;key=surl" target="_blank" class="m" data-click="{'rsv_comments':'1'}" data-from="ps_pc4">378條評價</a></span></div></div></div></div>

總結:這就是典型的非結構化數據

當然了還有一種半結構化數據,這裏不得不提,爬蟲也是經常遇到。

半結構化數據

半結構化數據是指:是結構化數據的一種形式,雖不符合關係型數據庫或其他數據表的形式關聯起來的數據模型結構,但包含相關標記,用來分隔語義元素以及對記錄和字段進行分層。因此,也被稱爲自描述的結構。比如xml跟json,如下代碼就是json格式

json文件:
{
    "name":"王小二""phone":"13624568542",
	"address":"陝西"

}

那麼可以用什麼進行處理呢?

非結構化的數據處理

:可以使用正則表達式,Xpath,css,對網頁源碼進行處理

結構化的數據處理

:如果這個表在網頁上依然得使用Xpath,css選擇器,正則表達式,當然如果在數據庫中,那麼就極爲方便,增加鍵值也是十分方便的。

半結構化的數據處理

:從網頁獲取的json數據文本轉換爲json格式,使用python進行取值等操作
在這裏插入圖片描述
咳咳,好了好了,說重點
說了這麼多,大家都知道學正則可以做什麼?我們今天就要來學習正則。加油!

python re模塊

什麼是正則表達式

:通常被用來檢索,替換哪些符合某個模式或規則的文本

正則表達式可以做什麼?

:正如概念所說,無非是匹配與過濾,記住正則永遠在做這兩件事,要麼生要麼死!

正則匹配一般必要步驟

在這裏插入圖片描述
總結:正則表達式引擎編譯表達式字符串得到的對象,包含應如何匹配得信息,正則表達式對象對文本進行匹配後得到的結果,包含了這次成功匹配的信息,可以得到匹配後的字符串,以及group()分組,span()索引信息等

提供幾個正則開發時,用得到的網站!

請點我
請點我
請點我
溫馨提示:具體用法,請自我研究,這裏就不一一講解!

compile函數

compile函數用來幹嘛的呢?
:compile用於編譯正則表達式,生成一個Pattern對象,PatternPattern對象包括:match方法,search方法,findall方法,finditer方法,split方法,sub方法,這些常用方法將再下面逐一講解。

溫馨提示:下面講解的方法都運行了compile函數,也可以不用。

match方法

那麼match方法的語法格式是什麼樣的呢?
match(string[, pos[, endpos]])
參數詳解
string 是待匹配的字符串,pos 和 endpos 是可選參數,指定字符串的起 始和終點位置,默認值分別是 0 和 len (字符串長度)。因此,當你不指定 pos 和 endpos 時,match 方法默認匹配字符串的頭部。
醉翁之意不在酒,在乎山水之間也!還是少廢話,看代碼

import re

# 只匹配一個數字
pattern1=re.compile(r'\d')
res1=pattern1.match("15236485624")
print(res1)

#匹配多個數字
pattern2=re.compile(r'\d+')
res2=pattern2.match("15236485624")
print(res2)

#沒匹配到的原因是,match默認從第一個匹配到最後一個,如果開頭不是數字直接返回None
pattern3=re.compile(r'\d+')
res3=pattern3.match("phone1:15236485624")
print(res3)

#匹配hello,並忽略大小寫
pattern4=re.compile(r'([a-z]+)([a-z+])',re.I)
res4=pattern4.match('HelLo world')
print(res4)

#加上pos跟endpos參數即可成功匹配,本代碼可以只添加pos參數也是可以endpos用默認的
pattern5=re.compile(r'\d+')
res5=pattern5.match("phone1:15236485624",7,18)
print(res5)

pattern6=re.compile(r'(\d{11}) (\d{11})')
res6=pattern6.match('15236485624 45684953624')
print(res6)

#查看匹配成功的整個字符串
print(res6.group(0))

#查看匹配成功的第一個分組匹配成功的字符串
print(res6.group(1))

#查看匹配成功的第一個分組匹配成功的字符串
print(res6.group(2))

#返回元組類型的所有組匹配成功的字符串
print(res6.groups())

#返回匹配成功的第一個分組匹配成功的字符串的起始位置
print(res6.start(1))

#返回匹配成功的第一個分組匹配成功的字符串的結束位置
print(res6.end(1))

#返回匹配成功的第一個分組匹配成功的字符串起始與終止索引,以元組形式返回
print(res6.span(1))

#返回匹配成功的第二個分組匹配成功的字符串的起始位置
print(res6.start(2))

#返回匹配成功的第二個分組匹配成功的字符串的結束位置
print(res6.end(2))

#返回匹配成功的第二個分組匹配成功的字符串起始與終止索引,以元組形式返回
print(res6.span(2))

#使用start函數查看匹配的pos參數
print(res6.start())

# 使用end()函數查看匹配的endpos參數
print(res6.end())

#以元組的形式查看pos參數跟endpos參數
print(res6.span())
'''
運行結果:

<re.Match object; span=(0, 1), match='1'>
<re.Match object; span=(0, 11), match='15236485624'>
None
<re.Match object; span=(0, 5), match='HelLo'>
<re.Match object; span=(7, 18), match='15236485624'>
<re.Match object; span=(0, 23), match='15236485624 45684953624'>
15236485624 45684953624
15236485624
45684953624
('15236485624', '45684953624')
0
11
(0, 11)
12
23
(12, 23)
0
23
(0, 23)
'''

單獨使用match方法

import re

#單獨使用match函數
#只匹配一個數字
res1=re.match(r'\d',"15236485624")
print(res1)
print(res1.group())

'''
運行結果:

<re.Match object; span=(0, 1), match='1'>
1
'''

search方法

那麼search方法的語法格式是什麼樣的呢?

search(string[, pos[, endpos]])

參數詳解
string 是待匹配的字符串,pos 和 endpos 是可選參數,指定字符串的起 始和終點位置,默認值分別是 0 和 len (字符串長度)。 當匹配成功時,返回一個 Match 對象,如果沒有匹配上,則返回 None。
醉翁之意不在酒,在乎山水之間也!還是繼續少廢話,看代碼

import re

#匹配字符串中的電話號碼,這裏注意:在match方法中是匹配不到的,並且是一次匹配
#匹配phone_one的電話號碼
pattern1=re.compile("\d+")
res1=pattern1.search('phone_one:14523564895 phone_two:48625486945')
print(res1)

#匹配phone_two的電話號碼
pattern2=re.compile("\d+")
res2=pattern2.search('phone_one:14523564895 phone_two:48625486945',21,)
print(res2)

#查看匹配的數據
print(res2.group())

#查看匹配的起始位置
print(res2.start())

#查看匹配的終止位置
print(res2.end())

#查看匹配的數據在原字符串中的起始位置與結束位置
print(res2.span())

'''
運行結果:

<re.Match object; span=(10, 21), match='14523564895'>
<re.Match object; span=(32, 43), match='48625486945'>
48625486945
32
43
(32, 43)
'''
'''

單獨使用search方法

import re

#單獨使用search函數
#匹配phone_one的電話號碼
pattern1=re.compile("\d+")
res1=re.search(r'\d+','phone_one:14523564895 phone_two:48625486945')
print(res1)
print(res1.group())

'''
運行代碼:

<re.Match object; span=(10, 21), match='14523564895'>
14523564895
'''

findall方法

那麼findall方法的語法格式是什麼樣的呢?

findall(string[, pos[, endpos]])

參數詳解
string 是待匹配的字符串,pos 和 endpos 是可選參數,指定字符串的起 始和終點位置,默認值分別是 0 和 len (字符串長度)。 findall 以列表形式返回全部能匹配的子串,如果沒有匹配,則返回一個空列表。

常用元字符:

元字符 含義
. 匹配除換行符以外的任意一個字符
^ 匹配行首
$ 匹配行尾
重複匹配0次或1次
* 重複匹配0次或更多次
+ 重複匹配1次或更多次
{n,} 重複n次或更多次
{n,m} 重複n~m次
[a-z] 匹配[a-z]任意字符
[abc] a/b/c中的任意一個字符
{n} 重複n次
\b 匹配單詞的開始和結束
\d 匹配數字
\w 匹配字母,數字,下劃線
\s 匹配任意空白,包括空格,製表符(Tab),換行符
\W 匹配任意不是字母,數字,下劃線的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非數字的字符
\B 匹配不是單詞開始和結束的位置
[^a] 匹配除了a以外的任意字符
[^(123|abc)] 匹配除了123或者abc這幾個字符以外的任意字符

代碼示例:

import re

#findall用法
#\d匹配數字,將匹配的數據以列表形式返回
pattern1=re.compile("\d")
result1=pattern1.findall("hello 123 567")
print(result1)

#\d+匹配一個或者多個數字,如果是多個數字,則必須連續
pattern2=re.compile('\d+')
result2=pattern2.findall("hello 124 567 eu98de")
print(result2)

#\d{3,}匹配3次或者多次必須多次,必須連續
pattern3=re.compile("\d{3,}")
result3=pattern3.findall("hellp 123 456 uu44jk655")
print(result3)

#\d{3}連續匹配3次
pattern4=re.compile("\d{3}")
result4=pattern4.findall("hellp 123 456 uu44666jk633")
print(result4)

#\d{1,2}可以匹配一次,也可以匹配兩次,以更多的優先
pattern5=re.compile('\d{1,2}')
result5=pattern5.findall('hellp 123 456 uu4466jk633')
print(result5)

#re.I 表示忽略大小寫,[a-z]匹配a-z的字母5次
pattern6=re.compile("[a-z]{5}",re.I)
result6=re.findall('hello 123 456 uu4466jk633')
print(result6)

#\w+匹配數字,字母,下劃線,一次或者多次
pattern7=re.compile("\w+")
result7=pattern7.findall("hellp 123 456 uu4466jk633")
print(result7)

#\W匹配不是下劃線,字母,數字
pattern8=re.compile("\W+")
result8=pattern8.findall("hellp 123 456 uu4466jk633")
print(result8)

#[\w\W]+ 可以匹配所有的字符,一次或者多次
pattern8=re.compile('[\w\W]+')
result9=pattern8.findall("hellp 123 456 uu4466jk633")
print(result9)

#[abc]+ 匹配a或者b 或者c一次或者多次
pattern10= re.compile("[abc]+")
result10=pattern10.findall('abc 123 456 abc4466jk633')
print(result10)

#[^abc|123]+ 匹配不是abc或者123的字符
pattern11 = re.compile('[^abc|123]+')
result11 = pattern11.findall("hellp 123 456 uu4466jk633%^&*(")
print(result11)

#.*匹配任意字符,除了換行符
pattern12=re.compile(".*")
result12=pattern12.findall("hellp 123 456 uu4466jk633%^&*(\n")
print(result12)

#re.I表示忽略大小寫,[a-z]{5}匹配a-z得字母5次
#只查找字符串0-8之間得字符,要前不要後(左閉右開)
pattern13=re.compile('[a-z]{8}',re.I)
result13=pattern13.findall("hellOpython123 456 u4466Wjk633",0,8)
print(result13)

'''
運行結果:

['1', '2', '3', '5', '6', '7']
['124', '567', '98']
['123', '456', '655']
['123', '456', '446', '633']
['12', '3', '45', '6', '44', '66', '63', '3']
['hello']
['hellp', '123', '456', 'uu4466jk633']
[' ', ' ', ' ']
['hellp 123 456 uu4466jk633']
['abc', 'abc']
['hellp ', ' 456 uu4466jk6', '%^&*(']
['hellp 123 456 uu4466jk633%^&*(', '', '']
['hellOpyt']
'''

單獨使用findall方法

import re

#單獨使用findall方法
#\d匹配數字,將匹配的數據以列表形式返回
result1=re.findall(r"\d","hello 123 567")
print(result1)

'''
運行代碼:

['1', '2', '3', '5', '6', '7']

'''

finditer方法

finditer方法是什麼,怎麼這麼像前面講的findall啊?
:沒錯,你犀利的眼神,正是驗證了finder方法的行爲與findall是比較形似的,也是搜索整個字符串,獲得所有匹配的結果,但是,咳咳,他返回的是一個可迭代對象,那麼這裏我就說一下,可迭代對象與迭代器有什麼不同!列表與可迭代對象有什麼不同!

列表與可迭代對象有什麼不同

列表與可迭代對象有什麼不同?
:列表需要大量的空間,而可迭代對象不需要消耗內存空間,只有在你想看的時候,你可以揭開面紗去看一看!!!

可迭代器對象與迭代器有什麼區別(小白誤區)

可迭代對象與迭代器有什麼區別?
:首先可迭代對象包含迭代器,如果一個對象擁有了__iter__方法,他就是一個可迭代對象,如果一個對象擁有了next方法,他就是一個迭代器。那麼反之定義可迭代對象,必須實現__iter__方法;定義迭代器必須實現next方法

import re

pattern1=re.compile(r'\d+')
res1=pattern1.finditer("phone_one:78645893654,phone_two:789456123")
#打印的結果是一個迭代的對象需要遍歷取值
print(res1)

#進行遍歷取出匹配成功的值,與打印匹配成功字符串的索引
for i in res1:
    print("匹配成功的字符串{},匹配成功字符串的索引{}".format(i.group(),i.span()))

'''
運行結果:

<callable_iterator object at 0x000001B2A4FE0C88>
匹配成功的字符串78645893654,匹配成功字符串的索引(10, 21)
匹配成功的字符串789456123,匹配成功字符串的索引(32, 41)
'''

split方法

咦,這個split方法真熟悉啊,不就是這個分割嘛,返回列表形式的函數嗎?
:沒錯就是他,他也可以用於正則當中,正則配上這個函數,不是如魚得水嗎,不是躍然紙上的嗎,哈哈哈。
廢話少說,我知道醉翁之意不在酒,在乎山水之間也!!!

import re

#使用split進行分割爲列表
pattern1=re.compile(r'[\s\,\.]+')
res1=pattern1.split('a,b.c d')
print(res1)

'''
運行結果:

['a', 'b', 'c', 'd']
'''

單獨使用split方法

import re

#單獨使用split方法
#使用split進行分割爲列表
res1=re.split(r'[\s\,\.]+','a,b.c d')
print(res1)

'''
運行代碼:

['a', 'b', 'c', 'd']
'''

sub方法

之前不是學過一個替換的函數嗎?
:真聰明,之前的確有個替換的函數叫replace(),我們用一個例子來說明他的心有餘,而力不足之處吧!
例如:將字符串"電話號碼phone1:454-4562-1546請聯繫我,電話號碼phone2:789-456-123請聯繫我"中的中文與橫槓去掉,使用replace雖然可以完成但是異常複雜,稍微複雜一下,replace就失去作用了,讓我們看一下正則裏的sub()是如何替換的。
sub方法的語法是什麼
sub(repl, string[, count])
參數詳解
repl 可以是字符串也可以是一個函數:如果 repl 是字符串,則會使用 repl 去替換字符串每一個匹配的子串,並返回 替換後的字符串,另外,repl 還可以使用 id 的形式來引用分組,但不能使用編 號 0; 如果 repl 是函數,這個方法應當只接受一個參數(Match 對象),並返回一 個字符串用於替換(返回的字符串中不能再引用分組)。count 用於指定最多替換次數,不指定時全部替換。

代碼示例
count的用法

import re

#不加匹配次數參數,默認全部匹配
res1 = re.sub(r"([-]|[\u4e00-\u9fa5]+)",'',"電話號碼phone1:454-4562-1546請聯繫我,電話號碼phone2:789-456-123請聯繫我")
print(res1)

#只匹配一次
res2 = pattern3.sub('',"phone1:454-4562-1546,phone2:789-456-123",1)
print(res2)

'''
運行結果:

phone1:45445621546,phone2:789456123
phone1:4544562-1546,phone2:789-456-123
'''

總結:sub方法不加count參數,默認全部替換
repl參數的使用

import re

#使用函數用""替換-
pattern3=re.compile("([-])")
def function(m):
    return ""

print(pattern3.sub(function,"phone1:454-4562-1546,phone2:789-456-123"))

'''
運行結果:

phone1:45445621546,phone2:789456123
'''

引用分組的使用

import re

pattern2=re.compile(r"(\w+) (\w+)")
res=pattern2.search("hello1 123, hello2 456")
print(res)
#進行引用分組
res2=pattern2.sub(r'\2 \1',"hello1 123, hello2 456")
print(res2)

'''
運行代碼:

<re.Match object; span=(0, 10), match='hello1 123'>
123 hello1, 456 hello2
'''

單獨使用sub方法

import re

#使用函數用""替換-
res1 = re.sub(r"([-])",'',"phone1:454-4562-1546,phone2:789-456-123")
print(res1)

'''
運行代碼:

phone1:45445621546,phone2:789456123
'''

總結:使用函數返回值進行替換,使sub方法功能更加強大

search與match函數有什麼區別與不同?

:search比match較爲先進,search是任意位置開始匹配,返回的是match對象;而match只能從起始固定位置匹配,如果開頭就不符合,直接返回None
代碼示例:

import re

pattern1=re.compile("\d+")
res1=pattern1.search('phone_one:14523564895 phone_two:48625486945')
print(res1)

res2=pattern1.match('phone_one:14523564895 phone_two:48625486945')
print(res2)

'''
運行結果:

<re.Match object; span=(10, 21), match='14523564895'>
None
'''

如何快速匹配中文

如何快速匹配中文?
:在某些情況下,我們想匹配文本中的漢字,有一點需要注意的是,中文的 unicode 編碼範圍 主要在 [\u4e00-\u9fa5]+,這裏說主要是因爲這個範圍並不完 整,比如沒有包括全角(中文)標點,不過,在大部分情況下,應該是夠用的。

代碼示例

import re

#進行中文的匹配
pattern=re.compile('\u4e00-\u9fa5')
res=pattern.findall("python:蟒蛇")
print(res)

'''
運行結果:

['蟒蛇']
'''

貪婪模式與非貪婪模式

什麼是貪婪模式?
:貪婪模式:在整個表達式匹配成功的前提下,儘可能多的匹配 ( * )
什麼是非貪婪模式?
:非貪婪模式:在整個表達式匹配成功的前提下,儘可能少的匹配 ( ? )
注意:python裏數量詞默認是貪婪的!
代碼示例:

import re
#貪婪模式,儘可能多的匹配c,所以全部匹配了c
pattern1=re.compile(r'abbc*')
res1=pattern1.findall(r'abbccc')
print(res1)

#非貪婪模式,儘可能的少匹配c,所以只匹配了一個c
pattern2=re.compile(r'abbc*?')
res2=pattern2.findall(r'abbccc')
print(res2)

'''
運行代碼:

['abbccc']
['abb']
'''

正則匹配大括號與中括號與小括號的區別總結

博主,我有個埋藏了好久的問題想問你?就是能不能說一下,正則匹配大括號與中括號與小括號的區別?
我隨聲答道
()是提取匹配的字符串,表達式中有幾個()就有幾個相應的匹配的字符串結果,一般使用group()查看.
[]是定義匹配的字符範圍,比如[a-z],當然了你也可以這樣[a,b,c,d,e,f…],也可以進行取反比如[^a],另外中括號裏的字符不再有特殊的含義,比如[.*]代表匹配.或者*。
{}一般用來表示匹配的長度,比如{1}只匹配一次,{1,2}最少匹配一次,最多匹配兩次。

注意:正則項目講解,將再下一篇文章中娓娓道來,還請客觀耐心等待!!

來一波,推送吧!
羣號:781121386
羣名:人生苦短,我學編程
歡迎大家加入我們,一起交流技術!!!

在這裏插入圖片描述

發佈了39 篇原創文章 · 獲贊 139 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章