0
雷鋒網(wǎng) AI 科技評論按,數(shù)據(jù)是所有機器學(xué)習問題的核心。如果不能訪問相關(guān)數(shù)據(jù),那么現(xiàn)在使用機器學(xué)習所取得的所有進展都是不可能的。盡管如此,如今大多數(shù)機器學(xué)習愛好者專注于獲取方法論知識(這是一個很好的開始,但不是一直如此)。
當方法論達到一定程度時,僅解決數(shù)據(jù)集可用的問題就限制了其潛力。
幸運的是,我們生活在一個網(wǎng)絡(luò)上有大量數(shù)據(jù)可用的時代,我們所需要的只是識別和提取有意義的數(shù)據(jù)集的技能。對此,亞馬遜工程師 Rishabh Misra 分享了他關(guān)于如何識別、抓取和構(gòu)建一個高質(zhì)量的機器學(xué)習數(shù)據(jù)集的心得,雷鋒網(wǎng) AI 科技評論編譯整理如下。
本文的重點是通過真實的案例和代碼片段解釋如何構(gòu)建高質(zhì)量的數(shù)據(jù)集。
本文將參考作者收集的三個高質(zhì)量數(shù)據(jù)集,即服裝尺寸推薦數(shù)據(jù)集、新聞類別數(shù)據(jù)集和諷刺檢測數(shù)據(jù)集來解釋不同的點。下面先簡要地解釋每個數(shù)據(jù)集是關(guān)于什么的。
服裝尺寸推薦數(shù)據(jù)集
服裝尺寸推薦和合身度預(yù)測對于改善顧客的購物體驗和降低產(chǎn)品返工率至關(guān)重要。從 ModCloth 收集的數(shù)據(jù)集包含客戶對其購買的服裝是否合適的反饋,以及諸如評級、評論、類別信息、客戶度量等其他方面的信息。這個數(shù)據(jù)集在識別決定服裝產(chǎn)品是否適合客戶的關(guān)鍵特征方面很有用。
新聞類別數(shù)據(jù)集
該數(shù)據(jù)集包含從 HuffPost 獲得的 2012 至 2018 年約 20 萬條新聞的標題。它包含諸如新聞類別、新聞標題、新聞故事的簡短描述、出版日期等詳細信息。數(shù)據(jù)集可以用于多種用途,如識別未跟蹤的新聞文章的標簽、識別不同新聞類別中使用的語言類型等。
諷刺檢測數(shù)據(jù)集
過去關(guān)于諷刺檢測的研究大多是利用基于 hashtag 的監(jiān)督收集的 twitter 數(shù)據(jù)集,但這些數(shù)據(jù)集在標簽和語言方面存在噪音。為了克服這些限制,這個數(shù)據(jù)集是從兩個新聞網(wǎng)站收集的:TheOnion 和 HuffPost。TheOnion 制作了當前事件的諷刺版本,而 HuffPost 則報道了真實和非諷刺的新聞。
一個有趣的事實是:這些數(shù)據(jù)集在 Kaggle 上共有超過 250 個贊、50k+次瀏覽、6000+次下載和 50+個提交者。
步驟1:搜索數(shù)據(jù)
這個階段需要耐心,因為你可能需要廣泛地進行網(wǎng)絡(luò)搜索。但你不用擔心。在這里,我將根據(jù)我的經(jīng)驗提供一些指導(dǎo),使您的搜索更加系統(tǒng)和高效。
如果您希望收集和構(gòu)建一個高質(zhì)量的數(shù)據(jù)集,那么您可能處于以下兩種情況之一:
您正在尋找一個數(shù)據(jù)集去解決特定的問題 [已知問題]。
您正在尋找可用于解決有趣問題的數(shù)據(jù)集 [未知問題]。
根據(jù)您所處的情況,以下指南將很有幫助。
已知問題
收集服裝合身度和諷刺檢測數(shù)據(jù)集,以解決特定的問題。
以下步驟可能有助于在這種情況下搜索數(shù)據(jù)集:
分解問題以識別解決問題所必需的數(shù)據(jù)信號:這是最重要的一步。在尺寸推薦問題的情況中,如果我們想向客戶推薦服裝尺寸,那么最重要的數(shù)據(jù)信息將是用戶 ID、產(chǎn)品 ID、購買的尺寸以及客戶對本次購買尺寸是否合適的反饋。其他信息,如產(chǎn)品類別、客戶測量等,有了更好但也不是必須的。
在網(wǎng)絡(luò)上搜索一個提供所有必要信息的來源:在這里,你的谷歌搜索技巧會派上用場。使用它可以瀏覽多個網(wǎng)站,并查看它們是否提供必要的數(shù)據(jù)信息。對于服裝尺寸匹配數(shù)據(jù)集,像 Zappos 這樣的網(wǎng)站似乎很有希望,但缺少基本的購買尺寸信息,而 ModCloth 確實提供了所有基本數(shù)據(jù)信息(盡管需要進行一些額外的調(diào)整,稍后將詳細介紹)。
如果找不到單個數(shù)據(jù)源,請查看是否可以組合多個數(shù)據(jù)源的數(shù)據(jù)來構(gòu)建數(shù)據(jù)集:諷刺檢測數(shù)據(jù)集是將多個源的數(shù)據(jù)組合起來以構(gòu)建完整且質(zhì)量良好的數(shù)據(jù)集的完美示例。因為我們知道問題(發(fā)現(xiàn)諷刺)和我們想要的數(shù)據(jù)類型(諷刺和非諷刺文本),所以我們不必堅持用一個數(shù)據(jù)源來提供所有信息。我將 TheOnion 確定為獲取諷刺文本的來源,而對于非諷刺文本,我選擇了一個真正的新聞報道網(wǎng)站 HuffPost。
查看數(shù)據(jù)源是否包含足夠的歷史數(shù)據(jù),以允許您構(gòu)造足夠大的數(shù)據(jù)集:這也是在開始收集數(shù)據(jù)之前需要考慮的一個非常重要的點。如果一個網(wǎng)站沒有足夠的數(shù)據(jù),例如,一個在線零售商沒有大量的產(chǎn)品可提供,或者如果一個新聞網(wǎng)站不包含對舊故事的存檔,那么即使你收集了這些數(shù)據(jù),它也不會給你帶來多大好處。所以,尋找一個提供足夠數(shù)據(jù)的數(shù)據(jù)源來構(gòu)造足夠大的數(shù)據(jù)集。
如何改進數(shù)據(jù)集?你能把其他來源的數(shù)據(jù)結(jié)合起來使它更有趣嗎?檢查完上述所有點后,看看如何進一步改進數(shù)據(jù)集。思考一下,您是否可以通過不同的數(shù)據(jù)源組合有關(guān)某些屬性的更多信息,這些信息可能會幫助人們?yōu)樗麄兊哪P蜆?gòu)建特性。
未知問題
在解釋這些類型情況的時候,新聞類別數(shù)據(jù)集是一個很好的選擇。不知道要找的是什么會使情況稍微復(fù)雜一點,但是,當您在瀏覽網(wǎng)頁時注意以下幾點可以幫助您識別下一個有趣的數(shù)據(jù)集:
數(shù)據(jù)源是否包含任何值得估計/預(yù)測的數(shù)據(jù)信號?:分析網(wǎng)站時,請考慮網(wǎng)站是否提供了任何值得評估的有趣信息。它可以是一些直接的東西,或者與網(wǎng)站上的信息類型有關(guān)的東西。
一個直截了當?shù)睦邮牵以?HuffPost 上注意到,每個故事都被進行了分類(如體育、政治等),而我認為預(yù)測分類將是一個有趣的問題。對于信息類型的案例,我將 HuffPost 的新聞標題視為諷刺檢測數(shù)據(jù)集中的非諷刺性句子(假設(shè)他們報道的是真實新聞),而將 TheOnion 的標題視為諷刺性句子。
數(shù)據(jù)源是否包含足夠的元數(shù)據(jù),這些元數(shù)據(jù)在預(yù)測結(jié)果時是否有用?一旦您選定了一個值得預(yù)測的數(shù)據(jù)信息,您就必須確保站點為您提供足夠的可用于預(yù)測該數(shù)據(jù)信息的相關(guān)信息,如果不是,您是否可以使用其他數(shù)據(jù)源將該信息帶到數(shù)據(jù)集中。例如,如果我們沒有關(guān)于商品的元數(shù)據(jù),那么在電子商務(wù)平臺上預(yù)測產(chǎn)品價格的效果可能不會很好。為了使數(shù)據(jù)集成為一個好的數(shù)據(jù)集,需要足夠的相關(guān)信息。
站點是否包含足夠的歷史數(shù)據(jù),讓你可以構(gòu)建足夠大的數(shù)據(jù)集?這與「已知問題」部分中的第 4 點相同。
預(yù)測結(jié)果有什么重要的意義或應(yīng)用嗎?高質(zhì)量數(shù)據(jù)集的一個標志是,它還可以用于解決有趣的實際問題,或者能夠?qū)δ承┈F(xiàn)象提供有趣的見解。例如,基于新聞類別數(shù)據(jù)集構(gòu)建的分類器可以幫助識別任何散文的寫作風格(無論是政治、幽默等),幫助標記未跟蹤的新聞文章,提供對不同類型新聞的寫作風格差異的洞察等等。
交叉檢查以查看此類數(shù)據(jù)是否已經(jīng)可用。如果是,數(shù)據(jù)集是否在現(xiàn)有數(shù)據(jù)集上添加了任何內(nèi)容?這一步很重要,這樣你就知道你在貢獻一些獨特的東西,而不是一些已經(jīng)存在的東西。從這一步開始,在谷歌上簡單搜索就足夠了。
如何改進數(shù)據(jù)集?你能把其他來源的數(shù)據(jù)結(jié)合起來使它更有趣嗎?這與「已知問題」部分中的第 5 點相同。
步驟 2:提取數(shù)據(jù)
一旦縮小了數(shù)據(jù)源范圍,我們就可以開始提取數(shù)據(jù)了。
在抓取數(shù)據(jù)之前,請仔細閱讀網(wǎng)站的條款,以確保您不會因為抓取和公開分發(fā)數(shù)據(jù)而違反法律規(guī)則。
由于在不舉實際例子的情況下很難解釋這一節(jié),因此我將以我在從 ModCloth 獲取數(shù)據(jù)時使用的腳本為例來闡述不同的觀點。
了解網(wǎng)站的結(jié)構(gòu)
首先要做的是熟悉站點的結(jié)構(gòu)。
在 ModCloth 上,我們看到在網(wǎng)站頂部有各種服裝類別:連衣裙、上衣、下裝等等。如果我們單擊其中一個類別(如上圖中的頂部),就會看到產(chǎn)品以網(wǎng)格格式顯示。圖片中的頁面顯示 100 個產(chǎn)品,其余產(chǎn)品可通過滾動右上角附近的頁面滾動器訪問。
接下來,我們單擊其中一個產(chǎn)品來觀察每個產(chǎn)品的頁面是什么樣子的。在頂部,我們有與項目相關(guān)的元數(shù)據(jù),在底部,我們有產(chǎn)品評論。
我們注意到每一頁最多包含 10 條評論。如果評論超過 10 條,我們會在右下角看到「NEXT」按鈕。
當我們單擊「NEXT」按鈕時,將顯示接下來的 10 條評論。但是,您可能會注意到鏈接沒有更改,這意味著除了單擊「NEXT」按鈕之外,沒有其他方法可以訪問后續(xù)評論。我們還可以看到,在隨后的頁面中,還會出現(xiàn)「PREVIOUS」按鈕。稍后我們將知道為什么這些細節(jié)對于數(shù)據(jù)提取很重要。
我們現(xiàn)在對網(wǎng)站的結(jié)構(gòu)有了相當好的了解。重申一下,我們的目標是從每個類別中提取每個產(chǎn)品的評論。
提取產(chǎn)品鏈接
由于類別數(shù)量有限,因此不需要編寫腳本來提取鏈接,我們可以手動收集這些鏈接。在本節(jié)中,我們將重點從服裝類別之一:上衣中提取產(chǎn)品鏈接。
要了解數(shù)據(jù)提取的基礎(chǔ)知識,請瀏覽以下博客:如何使用 pytho 和 BeautifulSoup 提取網(wǎng)站數(shù)據(jù)
我們還將利用瀏覽器自動化工具 Selenium 進行數(shù)據(jù)提取。
要了解 Selenium 的工作原理,請瀏覽以下博客:使用 Selenium 提取網(wǎng)站數(shù)據(jù)。
那么,讓我們開始吧:
到目前為止,我們知道在每個類別中,產(chǎn)品以每組 100 個的形式呈現(xiàn),我們可以滾動頁面滾動器來訪問所有產(chǎn)品。首先,我們需要了解不同頁面的鏈接是如何變化的。通常情況下,以下圖片建議使用遵循一個模式的鏈接。
頁面 1
頁面 2
頁面 3
然后,對于每個頁面,我們需要提取到單個項目的頁面的鏈接。為此,請轉(zhuǎn)到其中一個項目,右鍵單擊該項目并轉(zhuǎn)到「inspect」選項。滾動滾動條以識別包含 item 鏈接的<a>元素并注意其 css 類。在下面的圖片中,我們看到在我們的例子中,類是虛鏈接。最有可能的是,所有其他產(chǎn)品鏈接也將使用相同的類進行樣式設(shè)計(只需驗證一次)。
有了這些信息,我們可以編寫以下代碼來提取 Tops 類別中所有產(chǎn)品的鏈接:
from selenium import webdriver
from bs4 import BeautifulSoup
# download driver from http://chromedriver.chromium.org/downloads
path_to_chromedriver = './chromedriver2.exe'
browser = webdriver.Chrome(executable_path = path_to_chromedriver)
urls = []; counter = 0; tops_link = []
## Since Tops category has 7 pages, link to each following a specific pattern,
## we can create links to pages in following way.
for i in range(7):
urls.append('https://www.modcloth.com/shop/tops?sz=102&start='+str(counter))
counter += 102
## Extracting links for products in each page
for url in urls:
## open the url
browser.get(url)
## purposeful wait time to allow website to get fully loaded
time.sleep(4)
## get page content
content = browser.page_source
soup = BeautifulSoup(content, "lxml")
product_links = []
## extract all the "a" elements with "thumb-link" class from the page
data_links = soup.find_all("a", {"class":"thumb-link"})
## from each <a> element, extract the URL
for i in data_links:
product_links.append(i['href'])
tops_link.extend(product_links)
## purposeful wait time to avoid sending requests in quick succession
time.sleep(10)
正如您所注意到的,腳本有等待時間,以確保我們不會向站點太頻繁地發(fā)送請求。通常,每秒一個請求是合適的,但是考慮到 ModCloth 是一個小站點(可能沒有亞馬遜那么大),我們可以將等待時間延長。在這方面你可以運用你的判斷力。
提取評論
既然我們已經(jīng)為每個產(chǎn)品建立了一個鏈接,那么我們就可以更深入地了解每個產(chǎn)品的評論。首先,我們將檢查每個評論對應(yīng)的 HTML。再次,右鍵單擊查看并單擊「inspect」。
我們注意到每個評論都包含在<article>元素中。讓我們來探索一下<article>元素的構(gòu)成。我們可以通過單擊元素旁邊的箭頭來實現(xiàn)這一點。當我們將鼠標懸停在<article>標記內(nèi)的各個元素上時,相應(yīng)的視圖將在網(wǎng)頁上突出顯示。
例如,在上面的圖像中,具有名為「pr-rd-content-block pr-accordion pr-accordion-collapsed」的類的<section>元素折疊對應(yīng)于尺寸反饋意見和與客戶測量相關(guān)的數(shù)據(jù)。請參閱下面的腳本以了解如何提取<article>里面所有相關(guān)內(nèi)容的詳細信息。
from selenium.common.exceptions import NoSuchElementException, WebDriverException
import numpy as np
import random
## helper function to consolidate two dictionaries
def merge_two_dicts(x, y):
z = x.copy() # start with x's keys and values
z.update(y) # modifies z with y's keys and values & returns None
return z
scraped_data = []
## for each product in Tops category
for iterr in range(0,len(tops_link)):
init = 0
url = tops_link[iterr]
## open the URL in browser
try:
browser.get(url)
time.sleep(4)
except WebDriverException: ## when extracted URL is invalid
print('invalid url', iterr)
continue
## get the webpage content
content = browser.page_source
soup = BeautifulSoup(content, "lxml")
## repeat until we run of review pages
while(True):
## get the webpage content
content = browser.page_source
soup = BeautifulSoup(content, "lxml")
## extract reviewer details
reviewer_details = soup.find_all("div", {"class": "pr-rd-reviewer-details pr-rd-inner-side-cont ent-block"})
## extract reviewers' namereviewers_name = []
for reviewer in reviewer_details:
## In ModCloth, reviewer name appears as "By REVIEWER_NAME"
## Splitting at the end is to remove "By" to get only the actual reviewer name
reviewer_name = reviewer.find("p", {"class":"pr-rd-details pr-rd-author-nickname"}).te xt.split('\n')[-1].strip()
reviewers_name.append(reviewer_name)
## extract "isVerified" information
isVerified = soup.find_all("span", {"class": "pr-rd-badging-text"})
## extract the fit feedback and customer measurements data (review_metadata)
review_data = soup.find_all("article", {"class": "pr-review"})
review_metadata_raw = []
for i in range(len(review_data)):
review_metadata_raw.append(review_data[i].find("div", {"class": "pr-accordion-conten t"}))
## extract HTML elements which contain review metadata
review_metadata_elements = [review_metadata_raw[i].find_all("dl", {"class", "pr-rd-def-list" })
if review_metadata_raw[i] is not None else None
for i in range(len(review_metadata_raw))]
## extract actual data from HTML elements
review_metadata = []
for element in review_metadata_elements:
if element is None:
review_metadata.append(None)
continue
## <dt> elements contain metadata field name like "fit", "length" etc
## <dd> elements contain reviewer's response for those metadata fields like "small", "just right" etc
review_metadata.append([(element[i].find("dt").text.lower(), element[i].find("dd").text. lower())
if element is not None else ""
for i in range(len(element))])
## extract review text
review_text = [txt.text for txt in soup.find_all("p", {"class": "pr-rd-description-text"})]
review_summary = [txt.text for txt in soup.find_all("h2", {"class": "pr-rd-review-headline"})]
## extract item id
item_id = soup.find("div", {"class": "product-number"}).find("span").text
## extract item category
try:
category = soup.find("a", {"class":"breadcrumb-element"}).text.lower()
except AttributeError: ## if category not present, item is not available
time.sleep(15 + random.randint(0,10))
break
## extract available product sizes
product_sizes = [i.text.strip().lower() for i in soup.find("ul", {"class": "swatches size"})
.find_all("li", {"class": "selectable variation-group-value"})]
item_info = {"category": category, "item_id": item_id, "product_sizes": product_sizes}
## consolidate all the extracted data## ignore records which don't have any review metadata as fit feedback is an essential sig nal for us
scraped_data.extend([merge_two_dicts({"review_text": review_text[j], "review_summary":
review_summary[j]}, merge_two_dicts(merge_two_ dicts({
"user_name":reviewers_name[j]},
{data[0]:data[1] for data in review_metadata[j]})
,item_info))
for j in range(len(reviewer_details)) if review_metadata_raw[j] is not None])
## if current page is the initial one, it contains only NEXT button (PREVIOUS is missing)
if init == 0:
try:
init = 1
## execute click on NEXT by utilizing the xpath of NEXT
browser.execute_script("arguments[0].click();", browser.find_element_by_xpath ('//*[@id="pr-review-display"]/footer/div/aside/button')) time.sleep(10 + random.randint(0,5))
except NoSuchElementException: ## No NEXT button present, less than 10 reviews time.sleep(15 + random.randint(0,10))
break
else:
try:
## execute click on NEXT by utilizing the xpath of NEXT
## if you notice, the xpath of NEXT is different here since PREVIOUS button is also pre sent now
browser.execute_script("arguments[0].click();", browser.find_element_by_xpath('//*[@ id="pr-review-display"]/footer/div/aside/button[2]'))
time.sleep(10 + random.randint(0,5))
except NoSuchElementException: ## No NEXT button, no more pages left
time.sleep(15 + random.randint(0,10))
break
## save the extracted data locally
np.save('./scraped_data_tops.npy',scraped_data)
需要注意的幾點:
我們在許多地方做過異常處理。當我在運行腳本時遇到問題時,這些處理都會逐步添加進去。
第 30-97 行負責將感興趣的數(shù)據(jù)提取出來并解析為字典格式。通常,人們更喜歡將提取的數(shù)據(jù)存儲在本地并離線解析,但是,由于筆記本電腦的存儲空間限制,我更喜歡在線進行分析。
Selenium 在第 99-119 行中很有用。由于不同頁面的 URL 不會更改,所以導(dǎo)航的唯一方法是模擬按鈕單擊。我們已經(jīng)使用「NEXT」按鈕的 xpath 來完成同樣的工作。
xpath 可用于瀏覽 XML 文檔中的元素和屬性。要標識元素的 xpath,請轉(zhuǎn)到 inspect,右鍵單擊 HTML 代碼并復(fù)制 xpath,如下圖所示。
獲取 HTML 元素的 xpath 的方法;在本例中,為「NEXT」按鈕
這就完成了數(shù)據(jù)提取和分析過程,之后我們數(shù)據(jù)中的記錄將如下圖所示:
看起來,我們的工作已經(jīng)完成了。但是,仍然有幾個步驟可以構(gòu)建最終的數(shù)據(jù)集。
步驟 3:構(gòu)建數(shù)據(jù)集
到目前為止,我們所擁有的數(shù)據(jù)質(zhì)量在以下幾個維度上有一些改進空間:
數(shù)據(jù)清洗
到目前為止提取的數(shù)據(jù)可能缺少一些基本的數(shù)據(jù)信息或者記錄,謝謝數(shù)據(jù)可以被安全地處理掉。例如:
有很多關(guān)于 ModCloth 的評論,它們不包含是否合身的反饋或購買產(chǎn)品尺寸信息。盡管我們放棄了第 64-66 行中不包含任何相關(guān)信息的評論,但也存在一些包含相關(guān)信息但不包含某些基本數(shù)據(jù)信息的評論。
我們注意到,ModCloth 上評論人的信息并沒有和任何特定的 ID 關(guān)聯(lián)。這對我們來說是另一個挑戰(zhàn),因為用戶 ID 是必不可少的數(shù)據(jù)。為了解決這個問題,我們可以將評論者的昵稱與打分值連接起來,以形成一個唯一的字符串。我們可以字符串要求至少包含 3 個字段信息,以減少數(shù)據(jù)集中由于不同的評論者得到相同的 ID 而產(chǎn)生的干擾。然后就可以安全地刪除不存在此類信息的所有記錄。
此外,很少有記錄顯示產(chǎn)品目錄尺寸中沒有的采購尺寸(可能是報告錯誤),因此我們也拋棄了這些記錄。
匿名處理
為了保護隱私,需要對用戶和條目的詳細信息進行匿名處理。在 ModCloth 數(shù)據(jù)集中有一些敏感的屬性,比如身體尺寸數(shù)據(jù),我們可以隨機生成用戶 ID 和條目 ID。如果我們提取的是非公開的數(shù)據(jù)信息,這一點就變得更加重要了。
標準化
數(shù)據(jù)中可能存在一些屬性,這些屬性在所有記錄中的含義可能并不完全相同。在這種情況下,我們需要使用直覺(或一些基線)來標準化數(shù)據(jù)集中的屬性。例如,ModCloth 上的不同產(chǎn)品可能有不同的尺碼單位(比如牛仔褲在美國和中國有完全不同的尺碼單位)。因此,在我們標準化所有記錄的數(shù)據(jù)之前,數(shù)據(jù)集基本上是不可用的。
處理這一問題的一種方法是利用 ModCloth 上的尺寸表,它將不同單位的尺寸轉(zhuǎn)換為統(tǒng)一的標準。然而,有些產(chǎn)品中仍然存在一些單位未知的尺寸。我們可以利用我們的直覺將它們轉(zhuǎn)換為標準尺度,或者刪除數(shù)據(jù)不確定的評論。
結(jié)構(gòu)化
在我們完成了所有的預(yù)處理之后,我們要做的事情就是將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成常見的格式,如 csv、json 等,以便讓對數(shù)據(jù)集感興趣的人能夠很容易地讀取和導(dǎo)入數(shù)據(jù)。
結(jié)束語
完成上述所有步驟后,數(shù)據(jù)中的記錄可能如下圖所示:
吸收知識的最好方法就是動手實踐,所以同學(xué)們現(xiàn)在就可以找個數(shù)據(jù)集,開始練手啦!
via:https://towardsdatascience.com/a-practical-guide-to-collecting-ml-datasets-476f1ecf5e35
雷鋒網(wǎng)雷鋒網(wǎng)
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。