
用R語言做網(wǎng)頁爬蟲和文本分析
受到這篇情感分析的文章和這篇網(wǎng)頁爬蟲指南的雙重啟發(fā),我決定嘗試抓取并分析 Goodreads 網(wǎng)站的書評(píng)數(shù)據(jù)。這個(gè)項(xiàng)目將會(huì)呈現(xiàn)一個(gè)從數(shù)據(jù)收集到機(jī)器學(xué)習(xí)建模分析的完整案例,我在中途犯下的錯(cuò)誤也會(huì)一并呈現(xiàn)。本文將以5本流行的愛情故事書的評(píng)論為研究對(duì)象,我很自覺地選了同類型的書,使得評(píng)論具有可比性。這五本書也足夠暢銷,我們可以輕松獲取上千條評(píng)論,如果你不喜歡愛情故事,你也可以選擇其他類型的書做研究。
為了使這篇文章更易讀,我把它分成了三個(gè)部分:
Part 1: 網(wǎng)頁抓取
Part 2: 探索性數(shù)據(jù)分析和情感分析
Part 3: 基于機(jī)器學(xué)習(xí)的預(yù)測分析
這篇文章更新到了Part 1,后續(xù)部分會(huì)持續(xù)更新。
Part 1 網(wǎng)頁抓取
Goodreads上的評(píng)論很容易抓取,在每條評(píng)論左側(cè)都有一個(gè)非本文類型的排名變量。然而評(píng)論頁面的切換是通過一個(gè)javascript按鈕而不是html鏈接來實(shí)現(xiàn)的,處理起來有一點(diǎn)難度。不過好在這個(gè)問題有一個(gè)簡單有效的解決方法,只要使用RSelenium包就可以了,點(diǎn) 這里 可以閱讀該包的小品文。
起步
讓我們先加載好要用的包并定義幾個(gè)變量
library(data.table) # 為了rbindlist函數(shù)
library(dplyr) # 為了數(shù)據(jù)整理
library(magrittr) # 為了管道操作符 %>%
library(rvest) # 為了read_html函數(shù)
library(RSelenium) # 為了使用JavaScript進(jìn)行網(wǎng)頁抓取
url <- "https://www.goodreads.com/book/show/18619684-the-time-traveler-s-wife#other_reviews"
book.title <- "The time traveler's wife"
output.filename <- "GR_TimeTravelersWife.csv"
請注意,對(duì)每本書而言我需要改變上述變量的值并重新運(yùn)行腳本。如果你覺得麻煩,可以用代碼自動(dòng)實(shí)現(xiàn)這個(gè)過程,但此處我就采取手動(dòng)的做法。這么做也可以避免Goodreads'網(wǎng)站服務(wù)器過載。
讓我們啟動(dòng)RSelenium服務(wù)器,利用Firefox瀏覽器可能會(huì)有些問題,為此我重新安裝了一個(gè)比較舊的版本
startServer()
remDr <- remoteDriver(browserName = "firefox", port = 4444) # instantiate remote driver to connect to Selenium Server
remDr$open() # 打開瀏覽器
remDr$navigate(url)
這些指令會(huì)打開瀏覽器并轉(zhuǎn)向你制定好的url,之后我們需要建立一個(gè)數(shù)據(jù)框,方便后續(xù)數(shù)據(jù)的操作。
global.df <- data.frame(book=character(),
reviewer = character(),
rating = character(),
review = character(),
stringsAsFactors = F)
現(xiàn)在萬事俱備,可以開始網(wǎng)頁抓取了。
網(wǎng)頁抓取流程
為了提取我們需要的內(nèi)容,對(duì)于每本書,我們將掃描其100頁的評(píng)論。這里我去掉了循環(huán),只掃描一頁的內(nèi)容,并對(duì)代碼的工作原理逐行解釋。
首先,我們需要定義書評(píng)在頁面中的位置。使用SelectorGadget就能完成這一步驟,利用Chrome的一個(gè)拓展能幫助你識(shí)別CSS selector。只要找到了正確的CSS selector(這里是#bookReviews.stacked),將其傳遞給RSelenium服務(wù)器的findElements函數(shù)就可以了。
reviews <- remDr$findElements("css selector", "#bookReviews .stacked")
我們把書評(píng)的html代碼先提取出來,然后再分離其中的內(nèi)容。
reviews.html <- lapply(reviews, function(x){x$getElementAttribute("outerHTML")[[1]]})
reviews.list <- lapply(reviews.html, function(x){read_html(x) %>% html_text()} )
reviews.text <- unlist(reviews.list)
現(xiàn)在我們已經(jīng)用list的格式保存了評(píng)論,然而其中依舊混雜著很多無關(guān)內(nèi)容,我們需要利用正則表達(dá)式(regex)來清洗數(shù)據(jù)。
利用正則表達(dá)式清洗數(shù)據(jù)
依照我的文本分析經(jīng)驗(yàn),正則表達(dá)式既是天使也是魔鬼。通過它你可以用一行短短的命令就把字符串中所有的非字母元素移除,可它本身也是一門晦澀難懂的語言,使你在重讀自己的代碼時(shí)會(huì)倍感艱辛。所以如果你能讀懂下面的代碼做了些什么,我會(huì)倍感欣慰。
# 移除字母和符號(hào)外的元素
reviews.text2 <- gsub("[^A-Za-z\\-]|\\.+", " ", reviews.text)
# 移除換行符和多余的空格
reviews.clean <- gsub("\n|[ \t]+", " ", reviews.text2)
關(guān)于正則表達(dá)式,下面幾個(gè)網(wǎng)址很有用:
http://www.regular-expressions.info/
http://stat545.com/block022_regular-expression.html
https://stat.ethz.ch/R-manual/R-devel/library/base/html/regex.html
用表格格式存儲(chǔ)評(píng)論數(shù)據(jù)
現(xiàn)在我們已經(jīng)得到了很干凈的評(píng)論數(shù)據(jù),然而由于html暗含的數(shù)據(jù)結(jié)構(gòu),我們會(huì)遇到這樣的問題:對(duì)每一條評(píng)論,評(píng)論者的姓名和評(píng)分會(huì)存在同一個(gè)字符串里,而評(píng)論內(nèi)容存在后一個(gè)字符串中。此外,預(yù)覽評(píng)論系統(tǒng)會(huì)使得每個(gè)評(píng)論的開頭在字符串中重復(fù)出現(xiàn)兩次。我們需要對(duì)這些做做處理,再次使用正則表達(dá)式,我們將得到表格格式的數(shù)據(jù)。
我們先數(shù)數(shù)一共有多少條評(píng)論(即字符串?dāng)?shù)量的一半),然后建立一個(gè)臨時(shí)數(shù)據(jù)框來存儲(chǔ)數(shù)據(jù)。
n <- floor(length(reviews)/2)
reviews.df <- data.frame(book = character(n),
reviewer = character(n),
rating = character(n),
review = character(n),
stringsAsFactors = F)
我們遍歷所有的字符串,逐評(píng)論地提取需要的內(nèi)容并存在數(shù)據(jù)框里。這里我們采用for循環(huán)實(shí)現(xiàn)遍歷,但如果是工業(yè)級(jí)應(yīng)用,你應(yīng)該更喜歡向量化處理。
下面的代碼可能有點(diǎn)難懂,我先來解釋下:
1. 第一部分,我先列舉了可能出現(xiàn)在評(píng)論人姓名和評(píng)分之間的一些表達(dá)式,再結(jié)合正則表達(dá)式來確定姓名的結(jié)束位置,以此提取姓名。
2. 第二部分,我列舉了可以出現(xiàn)在評(píng)分之后的表達(dá)式,有時(shí)這些表達(dá)式并不會(huì)出現(xiàn),因此我得把這一情況也考慮進(jìn)去。通過這兩種方式,我們就可以提取評(píng)分了。
3. 第三部分,我把每個(gè)評(píng)論的開頭移除了,我會(huì)記錄50個(gè)字符重復(fù)出現(xiàn)的起始位置和結(jié)束位置。有時(shí),評(píng)論可能篇幅較短還不到50字符,這里就用和第二部分相似的方法處理。
4. 最后,請注意這個(gè)循環(huán)的結(jié)構(gòu),我并沒有一一循環(huán)字符串,而是遍歷了評(píng)論,每個(gè)評(píng)論包含兩個(gè)字符串,因此用2*j和2*j-1索引。
for(j in 1:n){
reviews.df$book[j] <- book.title
# 提取評(píng)論人姓名
auth.rat.sep <- regexpr(" rated it | marked it | added it ",
reviews.clean[2*j-1])
reviews.df$reviewer[j] <- substr(reviews.clean[2*j-1], 5, auth.rat.sep-1)
# 提取評(píng)分
rat.end <- regexpr("· | Shelves| Recommend| review of another edition",
reviews.clean[2*j-1])
if (rat.end==-1){rat.end <- nchar(reviews.clean[2*j-1])}
reviews.df$rating[j] <- substr(reviews.clean[2*j-1], auth.rat.sep+10, rat.end-1)
# 移除評(píng)論中重復(fù)的部分
short.str <- substr(reviews.clean[2*j], 1, 50)
rev.start <- unlist(gregexpr(short.str, reviews.clean[2*j]))[2]
if (is.na(rev.start)){rev.start <- 1}
rev.end <- regexpr("\\.+more|Blog", reviews.clean[2*j])
if (rev.end==-1){rev.end <- nchar(reviews.clean[2*j])}
reviews.df$review[j] <- substr(reviews.clean[2*j], rev.start, rev.end-1)
}
現(xiàn)在我們的臨時(shí)數(shù)據(jù)框已經(jīng)填寫完畢,我們可以把它的內(nèi)容轉(zhuǎn)移到主數(shù)據(jù)框中了。
global.lst <- list(global.df, reviews.df)
global.df <- rbindlist(global.lst)
最后,我們需要告訴RSelenium點(diǎn)擊進(jìn)入下一頁的按鈕,通過傳遞利用SelectorGadget定義CSS selector可以實(shí)現(xiàn)這個(gè)功能。同時(shí),Relenium的效率比較低,可能在循環(huán)中不能及時(shí)響應(yīng),因此我們在每個(gè)循環(huán)的末尾讓R等待3秒。
NextPageButton <- remDr$findElement("css selector", ".next_page")
NextPageButton$clickElement()
Sys.sleep(3)
結(jié)束所有循環(huán)后,我們要把最終結(jié)果保存成一個(gè)文件。
write.csv(global.df,output.filename)
最終結(jié)果如下:
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實(shí)戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動(dòng)態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價(jià)值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時(shí),“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗(yàn)與 t 檢驗(yàn):差異、適用場景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)領(lǐng)域,假設(shè)檢驗(yàn)是驗(yàn)證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計(jì)劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計(jì)劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對(duì)象的 text 與 content:區(qū)別、場景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請求開發(fā)時(shí)(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價(jià)值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請求工具對(duì)比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點(diǎn)數(shù)據(jù)的科學(xué)計(jì)數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點(diǎn)數(shù)據(jù)時(shí)的科學(xué)計(jì)數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價(jià)值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營問題、提升執(zhí)行效率的核心手段,其價(jià)值 ...
2025-09-12用 SQL 驗(yàn)證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計(jì)” 與 “用戶體驗(yàn) ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動(dòng)下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價(jià)值 在數(shù)據(jù)驅(qū)動(dòng)決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實(shí)踐到業(yè)務(wù)價(jià)值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計(jì)模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價(jià)值導(dǎo)向 統(tǒng)計(jì)模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10