初步處理爬取到的150708個單詞的數據(原始網頁文檔格式,包含注音、釋義與例句,等等)

目錄

前言:   

正文:


 

前言:   

   

       在正式介紹處理數據前先放出本次實驗所用服務器與筆記本的配置以及其他一些工具的版本信息。服務器配置:

 

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 79
Model name:            Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz
Stepping:              1
CPU MHz:               2494.222
BogoMIPS:              4988.44
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              40960K
NUMA node0 CPU(s):     0
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt

       

       筆記本配置:

 

Host Name:                 DESKTOP-UBDN0UL
OS Name:                   Microsoft Windows 10 Pro N for Workstations
OS Version:                10.0.18363 N/A Build 18363
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Workstation
OS Build Type:             Multiprocessor Free
Registered Owner:          hadoop001
Registered Organization:
Product ID:                00392-30000-00001-AA159
Original Install Date:     2020-01-29, 07:48:44
System Boot Time:          2020-05-02, 00:37:38
System Manufacturer:       Dell Inc.
System Model:              G3 3579
System Type:               x64-based PC
Processor(s):              1 Processor(s) Installed.
                           [01]: Intel64 Family 6 Model 158 Stepping 10 GenuineIntel ~2304 Mhz
BIOS Version:              Dell Inc. 1.2.1, 2018-07-18
Windows Directory:         C:\Windows
System Directory:          C:\Windows\system32
Boot Device:               \Device\HarddiskVolume5
System Locale:             en-us;English (United States)
Input Locale:              en-us;English (United States)
Time Zone:                 (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi
Total Physical Memory:     16,245 MB
Available Physical Memory: 7,745 MB
Virtual Memory: Max Size:  20,484 MB
Virtual Memory: Available: 3,122 MB
Virtual Memory: In Use:    17,362 MB
Page File Location(s):     C:\pagefile.sys
Domain:                    WORKGROUP
Logon Server:              \\DESKTOP-UBDN0UL
Hotfix(s):                 12 Hotfix(s) Installed.
                           [01]: KB4537572
                           [02]: KB4513661
                           [03]: KB4516115
                           [04]: KB4517245
                           [05]: KB4521863
                           [06]: KB4524244
                           [07]: KB4528759
                           [08]: KB4537759
                           [09]: KB4538674
                           [10]: KB4541338
                           [11]: KB4552152
                           [12]: KB4549951
Network Card(s):           3 NIC(s) Installed.
                           [01]: Realtek PCIe GbE Family Controller
                                 Connection Name: Ethernet
                                 Status:          Media disconnected
                           [02]: Intel(R) Wireless-AC 9462
                                 Connection Name: Wi-Fi
                                 DHCP Enabled:    Yes
                                 DHCP Server:     192.168.43.1
                                 IP address(es)
                                 [01]: 192.168.43.58
                                 [02]: fe80::852e:ffd6:7cee:e82
                           [03]: Bluetooth Device (Personal Area Network)
                                 Connection Name: Bluetooth Network Connection
                                 Status:          Media disconnected
Hyper-V Requirements:      VM Monitor Mode Extensions: Yes
                           Virtualization Enabled In Firmware: Yes
                           Second Level Address Translation: Yes
                           Data Execution Prevention Available: Yes

       

       PyCharm版本信息:

 

PyCharm 2019.3.4 (Professional Edition)
Build #PY-193.6911.25, built on March 18, 2020
Licensed to hadoop001

Runtime version: 11.0.6+8-b520.43 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0
GC: ParNew, ConcurrentMarkSweep
Memory: 1963M
Cores: 8
Registry: 
Non-Bundled Plugins: R4Intellij, aws.toolkit

     

       Python版本信息:

 

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32

       

       Oracle與PL/SQL版本信息:

 

PL/SQL Developer
  Version 13.0.6.1911  (64 bit)
  01.226959 - Unlimited user license
  Service Contract: 9999-12-31
  Windows 10 Build 18362
   
  Physical memory : 16,634,436 kB  (8,109,864 available)
  Paging file     : 20,975,672 kB  (3,284,548 available)
  Virtual memory  : 137,438,953,344 kB  (137,433,621,920 available)

Parameters
  D:\PLSQL Developer 13\plsqldev.exe

Preferences
  Session mode: Multi
  OCI Library: <none>
  Use OCI7: False
  Allow Multiple Connections: True

Preference Files
  D:\PLSQL Developer 13\Preferences\Default\Default.ini
  C:\Users\hadoop001\AppData\Roaming\PLSQL Developer 13\Preferences\hadoop001\default.ini

License File
  C:\Users\hadoop001\AppData\Roaming\PLSQL Developer 13\aalf.dat

Debug file
  D:\PLSQL Developer 13\PlSqlDev.elf

Plug-Ins
  *Active Query Builder (D:\PLSQL Developer 13\PlugIns\ActiveQueryBuilder.dll)
  *PL/SQL Documentation (plsqldoc) (D:\PLSQL Developer 13\PlugIns\plsqldoc.dll)
   (* is Active)

Aliases
  LISTENER_ORCL
  ORACLR_CONNECTION_DATA
  ORCL

Homes
  OraDB19Home1  (D:\WINDOWS.X64_193000_db_home)

DLLs
  D:\WINDOWS.X64_193000_db_home\bin\oci.dll

TNS File
  D:\instantclient_19_5\tnsnames.ora

Using
  Home: OraDB19Home1
  DLL: D:\WINDOWS.X64_193000_db_home\bin\oci.dll
  OCI: version 12.1  (19.3.0.0.0)
  Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 

Character Sets
  Character size: 4 byte(s)
  CharSetID: 873
  NCharSetID: 2000
  Unicode Support: True
  NLS_LANG: AMERICAN_AMERICA.AL32UTF8
  NLS_NCHAR_CHARACTERSET: AL16UTF16
  NLS_CHARACTERSET: AL32UTF8

Process
  Working Set = 132,890,624
  Memory = 33,325,392
  GDI Objects = 1525
  User Objects = 547
  Handles = 1065

Monitor
  PixelsPerInch = 120
   
  Id = 0
  PPI = 120
  Primary = True
  Handle = 65537
  Left = 0
  Top = 0
  Width = 1920
  Height = 1080
   
  MainFormOnTaskbar = True

 

正文:

 

       在服務器上運行一段很簡單的爬蟲,爬取了必應在線詞典的150708個單詞搜索結果的網頁,具體的代碼與步驟已經在上一篇博文

裏面介紹過了,此處不贅述。最終所得結果是150708個TXT文檔,博主將其按照原始單詞的數字前綴放到不同的文件夾,如圖1所

示。

圖1 被爬取的數據存放在不同文件夾中

 

        因如上一篇博文所述,我只是簡單地爬取了網頁的頁面HTML源代碼,沒有仔細處理JS等所包含的內容,因此文本中所含有效信

息很少,經過篩查發現:只有單詞的讀音和釋義是完整的信息,方便提取,例句等其他內容夾雜在很多標籤裏面,如圖2與圖3所示。

 

圖2 完整的單詞注音與釋義
圖3 相對零散的例句

 

       爲了提取各個文件中單詞的讀音與釋義,博主使用瞭如下代碼來處理,主要使用了正則表達式來匹配,代碼中有相應註釋。

 

#-*- coding : utf-8 -*-
# coding: utf-8

import re
import os

def openFile(path):
    fileNames = os.listdir(path)
    files = [] #目錄下所有文件的內容所構成的列表,形式爲:13_phytochemical.txt
    vocabularyList = [] #所有單詞組成的列表,也即文件名去掉前綴之後的形式
    prefixList = [] #所有文件名的前綴構成的列表

    cnt = 0
    for fileName in fileNames:
        file = open(path + fileName, encoding='UTF-8')
        vocabularyList.append(fileName.replace(".txt", ""))
        pretfix = re.search(r'^\d.*[_]', fileName, flags = 0) #匹配前綴
        prefixList.append(pretfix.group())
        st = file.read() #讀取整個文件
        cnt += 1
        files.append(st) #將新的文件內容添加到列表中

    return files, vocabularyList, prefixList #返回的是3個列表

def filterFiles(path):
    rule_name = r'content="必應詞典爲您提供.*; "'
    '''
    因爲我直接爬取的純HTML頁面,沒有處理cookie等內容(裏面包含了完整的例句、單詞聯想等),
    所以得到的文本很簡陋。看了之後發現只有給出的單詞釋義和讀音還比較完整,因此此處的正則表達式
    僅僅對其進行匹配。
    '''
    removeFiles = []
    '''
    我本來想着將單詞釋義與讀音提出出來另存爲文件後就把原來的文件刪了,但發現有些文件裏面包含了單詞釋義但並未被提取出來,
    還被直接給刪了。試了幾種方法,最終決定:
    先嚐試將存儲在文件夾A中的所有文件的單詞釋義提取出來,並以相同的文件名存儲在B文件夾,接着判斷在A文件夾中是否含有
    與B文件夾文件名相同的文件,如有則刪除。刪除操作應在單詞釋義提取之後立刻判斷是否進行,否則複製的文件會越來越多,最終可能
    超過服務器的承載極限。
    '''
    compile_name = re.compile(rule_name, re.M) #正則表達式匹配
    files, vocabularyList, prefixList = openFile(path)

    result = []
    for st in files:
        removeFiles.append(st)
        res_name = compile_name.findall(str(st))
        result += res_name
    return result, vocabularyList, prefixList, removeFiles #返回的是4個列表

def deleteFiles(removeFilePath, storageFilePath): #兩個路徑
    removeFiles = os.listdir(removeFilePath)
    for file in removeFiles:
        fuckFile = storageFilePath + file
        if os.path.exists(fuckFile):
            os.remove(fuckFile)

if __name__ == '__main__':
    for cnt in range(0, 21):
        removeFilePath = "/home/crawler/" + str(cnt) + "/" #store the original data
        storageFilePath = "/home/crawler/" + str(cnt) + "_result/" #store the accessed data

        lines, vocabularyList, prefixList, removeFiles = filterFiles(removeFilePath)
        for st in lines:
            mylog = open(storageFilePath + vocabularyList[cnt] + ".txt", mode = 'w', encoding = 'utf-8') #以相同文件名存儲在另一個文件夾
            print("word=" + "\"" + vocabularyList[cnt].replace(prefixList[cnt], "") + "\"" + "\n" + st, file = mylog)
            mylog.close() #關閉文件
            deleteFiles(storageFilePath, removeFilePath) #提取完可能存在的單詞釋義後,立即將原文件刪除
            cnt += 1 #接着使用餘下的單詞與文件名前綴

 

       值得一提的是,如上所示代碼在服務器上運行的過程中,極爲容易“卡死”——程序莫名其妙就不運行了,試了幾次都是如此。

博主曾經讓程序運行了一個晚上,到第二天早上還是沒有跑出什麼結果來,再次運行時居然還會報“列表訪問越界”的錯。因此,索

性便對代碼進行了簡單的修改:不用循環遍歷文件夾,而是每次執行完畢後手動修改再運行,如下所示。

#-*- coding : utf-8 -*-
# coding: utf-8

import re
import os

def openFile(path):
    fileNames = os.listdir(path)
    files = [] #目錄下所有文件的內容所構成的列表,形式爲:13_phytochemical.txt
    vocabularyList = [] #所有單詞組成的列表,也即文件名去掉前綴之後的形式
    prefixList = [] #所有文件名的前綴構成的列表

    cnt = 0
    for fileName in fileNames:
        file = open(path + fileName, encoding='UTF-8')
        vocabularyList.append(fileName.replace(".txt", ""))
        pretfix = re.search(r'^\d.*[_]', fileName, flags = 0) #匹配前綴
        prefixList.append(pretfix.group())
        st = file.read() #讀取整個文件
        cnt += 1
        files.append(st) #將新的文件內容添加到列表中

    return files, vocabularyList, prefixList #返回的是3個列表

def filterFiles(path):
    rule_name = r'content="必應詞典爲您提供.*; "'
    '''
    因爲我直接爬取的純HTML頁面,沒有處理cookie等內容(裏面包含了完整的例句、單詞聯想等),
    所以得到的文本很簡陋。看了之後發現只有給出的單詞釋義和讀音還比較完整,因此此處的正則表達式
    僅僅對其進行匹配。
    '''
    removeFiles = []
    '''
    我本來想着將單詞釋義與讀音提出出來另存爲文件後就把原來的文件刪了,但發現有些文件裏面包含了單詞釋義但並未被提取出來,
    還被直接給刪了。試了幾種方法,最終決定:
    先嚐試將存儲在文件夾A中的所有文件的單詞釋義提取出來,並以相同的文件名存儲在B文件夾,接着判斷在A文件夾中是否含有
    與B文件夾文件名相同的文件,如有則刪除。刪除操作應在單詞釋義提取之後立刻判斷是否進行,否則複製的文件會越來越多,最終可能
    超過服務器的承載極限。
    '''
    compile_name = re.compile(rule_name, re.M) #正則表達式匹配
    files, vocabularyList, prefixList = openFile(path)

    result = []
    for st in files:
        removeFiles.append(st)
        res_name = compile_name.findall(str(st))
        result += res_name
    return result, vocabularyList, prefixList, removeFiles #返回的是4個列表

def deleteFiles(removeFilePath, storageFilePath): #兩個路徑
    removeFiles = os.listdir(removeFilePath)
    for file in removeFiles:
        fuckFile = storageFilePath + file
        if os.path.exists(fuckFile):
            os.remove(fuckFile)

if __name__ == '__main__':
    for cnt in range(0, 21):
        removeFilePath = "/home/crawler/" + str(cnt) + "/" #store the original data
        storageFilePath = "/home/crawler/" + str(cnt) + "_result/" #store the accessed data

        lines, vocabularyList, prefixList, removeFiles = filterFiles(removeFilePath)
        for st in lines:
            mylog = open(storageFilePath + vocabularyList[cnt] + ".txt", mode = 'w', encoding = 'utf-8') #以相同文件名存儲在另一個文件夾
            print("word=" + "\"" + vocabularyList[cnt].replace(prefixList[cnt], "") + "\"" + "\n" + st, file = mylog)
            mylog.close() #關閉文件
            deleteFiles(storageFilePath, removeFilePath) #提取完可能存在的單詞釋義後,立即將原文件刪除
            cnt += 1 #接着使用餘下的單詞與文件名前綴

       

       如上所示代碼的不足就是每次運行都需要再手動修改程序中的變量值,即使如此,程序還是無法一次性將既定文件夾下的文件全

部處理完。

       博主原意擬生成的包含提取出的單詞注音與釋義的文件的格式是:

文件名:
5_grallatores.txt
文件內容:
word="grallatores"
content="必應詞典爲您提供steinbock的釋義,美[s'taɪnbɒk],英[s'taɪnbɒk],abbr. 同“ibex”;同“steenbok”; 網絡釋義: 北山羊;史坦巴克;摩羯星座; "

 

       在服務器上初步處理的結果與我的預想基本一致,但如處理代碼的註釋所述,有些文本本身含有單詞的注音與釋義,但程序每次

提取的過程中都會遺漏掉若干個文件:少則幾個,多則幾百個。不論實驗多少次,結果都是會有文本被遺漏。爲了圖省事,在服務器

上對所有文件處理了一遍之後,博主就將所有已經成功處理出的結果與遺漏的文件打包壓縮,下載到本地(使用工具FileZilla),再

另尋他法。

       對如上所示的第二段代碼稍作修改,便用在了本地提取內容的操作中,爲了避免遺漏處理的情況再次出現(但結果還是出現了)

和圖省事,博主索性將所有功能寫成一個“大雜燴”而不再寫成函數,具體如下所示。

#-*- coding : utf-8 -*-
# coding: utf-8

import re
import os
import sys

path = "E://Document/English_Learning_Materials/crawler/large/"


files = []
vocabularyList = []
# removeFiles = []
prefixList = []

tot = 0
fileNames = os.listdir(path)
for fileName in fileNames:
    file = open(path + fileName, encoding='UTF-8')
    vocabularyList.append(fileName.replace(".txt", ""))
    prefix = re.search(r'^\d.*[_]', fileName, flags=0)  # 匹配前綴
    prefixList.append(prefix.group())
    st = file.read()
    files.append(st)
    print(tot + 1)
    tot += 1

    # print(files)
rule_name = r'content="必應詞典爲您提供.*; "'
result = []
compile_name = re.compile(rule_name, re.M)
for st in files:
    res_name = compile_name.findall(str(st))
    result += res_name

print(result)
cnt = 0
for s1 in result:
    mylog = open(path + vocabularyList[cnt] + ".log", mode='w', encoding='utf-8')
    print("word=" + "\"" + vocabularyList[cnt].replace(prefixList[cnt], "") + "\"" + "\n" + s1, file = mylog)
    # removeFiles.append(vocabularyList[cnt] + ".txt")
    print("************")
    mylog.close()
    cnt += 1


# for x in removeFiles:
#     print(x)
#     fuckFile = str( path + x )
#     if os.path.exists(fuckFile):
#         os.remove(fuckFile)

 

       每次執行完畢後,都必須將.log文件及其與之同名的.txt文件移動到另一個文件夾,再運行代碼處理剩餘的TXT文件,幾個來回才

把所有文件處理完,本地運行預想的結果也是如上所示的格式。然而,這次卻出問題了,如圖4所示。

圖4 結果與預想不一致

 

       問題很明顯:所得的結果文件的標題與提取到的內容不匹配,同前幾次的經歷一樣,博主又反覆進行了幾次實驗,但結果依然如

此——太打擊蒟蒻了。不過幸虧博主從原始文件提取的是內容都是如下所示的格式:

content="必應單詞爲您提供..."

 

而不是直接將“單純”的釋義,這樣一來博主可以在“content”的內容中依次將單詞及其注音與釋義提取處理。思路和前面的差不

多,即:打開文件、正則表達式匹配、新建文件讀回提取到的內容,同時本次操作不再將每個單詞及其注音與釋義分別存放在不同的

文件,而是統一放在一個文件裏面。所用代碼如下所示。

 

#-*- coding : utf-8 -*-
# coding: utf-8

import re
import os
import sys

sourcePath = "E://Document/English_Learning_Materials/crawler/result/"
errorPath = "E://Document/English_Learning_Materials/crawler/"
resultPath = "E://Document/English_Learning_Materials/crawler/"

result = []
vocabularyList = []
removeFiles = []

rule_name = r'content="必應詞典爲您提供.*; "'
tot = 0
i = 0
compile_name = re.compile(rule_name, re.M)

fileNames = os.listdir(sourcePath)
# print(fileNames)
OMG_flag = -1

for fileName in fileNames:
    file = open(sourcePath + fileName, encoding='UTF-8')
    vocabularyList.append(fileName.replace(".txt", ""))
    prefix = re.search(r'^\d.*[_]', fileName, flags=0)  # 匹配前綴

    st = file.read()
    if( OMG_flag == -1 and st.find( "'", 0, len(st) ) ):
        print("OMG! NO!")
        OMG_flag += 1

    res_name = compile_name.findall(str(st))
    # print("res_name: " + str(res_name))
    if( len(res_name) != 0 ):
        result.append(res_name)

    if(len(res_name) == 0):
        removeFiles.append( fileName )
        print(tot + 1)
        print(vocabularyList[i])

        tot += 1

    print("Preprocessing: " + str(i + 1) )
    i += 1

    # if(tot > 3):
    #     break

cnt = 0
for s1 in removeFiles:
    mylog = open(errorPath + "error.log", mode='a', encoding='utf-8')
    print( str(cnt + 1) + "\n" + str(s1), file = mylog)
    #print("************")
    # print("s1 = " + s1)
    mylog.close()
    cnt += 1

myRule2 = r'content=.*釋義,'
compile_name2 = re.compile(myRule2, re.M)

myRule3 = r' "'
compile_name3 = re.compile(myRule3, re.M)

flag = -1;

# testDic = {}

finishCNT = 1

for s2 in result:
    myList = open(resultPath + "myDicts.csv", mode='a', encoding='utf-8')
    if(flag == -1):
        print("word,meaning,source", file=myList)
        flag += 1
    myDict = compile_name2.findall(str(s2))
    singleWord = str(myDict).replace("content=\"必應詞典爲您提供", "").replace("的釋義,","")
    # print(singleWord)
    crab = compile_name2.findall(str(s2))
    # print("crab: " + str(crab) )
    # print( "s2: " + str(s2) )
    OMG = compile_name3.search(str(s2))
    # print(OMG.group())
    meaning = str(s2).replace( crab[0], "" ).replace(OMG.group(), "")
    # testDic[singleWord] = meaning
    # print(meaning)
    print( str(finishCNT) + "\t" + str(singleWord) + "\t" + str(meaning) + "\t", file = myList) #爲了便於後續將.csv文件導入Oracle中,因此要在每行的末尾增加一個製表符“\t”

    myList.close()
    print("Finishing: " + str(finishCNT) )
    finishCNT += 1

 

       運行過程如圖5與圖6所示,運行正則表達式匹配(Processing計數)時的電腦硬件資源消耗如圖7所示,文件回寫(Finishing計

數)時的電腦硬件消耗情況如圖8所示。

 

圖5 程序運行正則表達式匹配

 

圖6 程序運行文件回寫
圖7 運行正則表達式匹配時的電腦硬件資源消耗情況

 

圖8 程序執行文件回寫時的電腦硬件資源消耗情況

 

       得到的.csv文件的部分結果如圖9與圖10所示。

 

圖9 提取出的單詞及其注音與釋義文件(局部)

 

圖10 提取出的單詞及其注音與釋義文件(局部)

 

        從圖9和圖10可以看出,由於在程序中直接將本應輸出到控制檯的信息寫到文本中,因此內容含有多餘的符號:“['”、"']"與

“\”,將這幾個符號完全剔除後的結果如圖11所示。

 

圖11 剔除多餘符號後的文本內容

 

        細心的朋友可能注音到了,生成的.csv文件中只有3個數據項,本應有2個製表符“\t”,但文本中每一行的末尾都還有1個製表

符“\t”,這主要是爲了方便後續將.csv文件導入到|Oracle數據中。

       用以下命令在Oracle數據庫中新建一張數據表,用於存儲單詞序號及其注音與釋義。注意:我爲了圖省事,並未將單詞的序號設

置爲自增主鍵(Oracle中凡是owner是sys的表都不能設置觸發器,而這是在Oracle中設置自增主鍵較爲簡單的辦法之一)。

 

CREATE TABLE vocabularyList150708(
word_ID number NOT NULL PRIMARY KEY,
single_Word VARCHAR(100) NOT NULL,
word_Meaning VARCHAR(1000) NOT NULL
);

 

       成功新建數據表後,使用PL/SQL的Text Importer工具將.csv文件導入到其中,過程非常簡單,不詳述。下面給出操作的截圖,

如圖12與圖13所示。


 

圖12 藉助PL/SQL將.csv文件導入Oracle數據步驟1

 

圖13 藉助PL/SQL將.csv文件導入Oracle數據步驟2

       經過一番折騰,終於搞出含有150708個英語單詞及其釋義與注音(少部分單詞無注音)的.sql文件,如圖14與圖15所示。後面可

能會考慮繼續完善,譬如添加例句等。

 

圖14 查詢數據表中的記錄數目

 

圖15 查詢數據表中的信息

 

       一番折騰,終於得到了.sql文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章