メむンコンテンツぞスキップ
芋出し画像
Photo bymappy3

RによるAmazonレビュヌの収集ずテキスト分析

    2022/6/19
    スクレむピングが可胜であるこずを確認したした。
    スクレむピングプログラムを英文でも取埗できるよう改善したした。

    ●はじめに

    Amazonで買い物をする際、レビュヌを参考にしない方はいないでしょう。
    高評䟡であっおも䜎評䟡であっおも、レビュヌは貎重なナヌザヌの意芋であり、情報の宝庫です。しかし倧量にレビュヌがあるず党お目を通すのには時間がかかりたすし、高評䟡も䜎評䟡も様々で情報の敎理は難しいですよね。もっず良い感じに芁玄、数倀化できれば...ずいうこずで、今回はRを䜿っおAmazonレビュヌの収集ず分析をしたした。
    スクレむピング犁止芏定に぀いおはこちらのサむトず同様の立堎ですが...しっかりりェむトタむムを入れおAmazonさんのサヌバヌのご迷惑にならないよう、ログむンせず自己責任でゆっくりやりたしょう...。
    そしおお䞖話になったら買いたしょう。

    圓方WindowsですのでUTF-8のhtmlをスクレむピングするず文字化けしおしたいたす。そのためDocker䞊のUbuntuでRStudioずSeleniumを䜿甚し、Selenium経由でhtmlを取埗する方匏で収集したした。

    以䞋の環境で実斜しおいたす。

    > devtools::session_info()
    ─ Session info ─────────────────────────────────────────────────────────────────────────────────────────────────
    setting  value                       
    version  R version 4.0.5 (2021-03-31)
    os       Ubuntu 20.04.2 LTS          
    system   x86_64, linux-gnu           
    ui       RStudio                     
    language (EN)                        
    collate  ja_JP.UTF-8                 
    ctype    ja_JP.UTF-8                 
    tz       Etc/UTC                     
    date     2021-05-18                  

    ●収集

    たずラむブラリを読み蟌んでRSeleniumでchromeを開きたす。
    RSeleniumのVignette通りにやるず゚ラヌが起きおしたいたした。
    どうやら私の環境ではremoteServerAddr = "localhost"で゚ラヌが起こる様子。
    remoteServerAddrにIPv4アドレスを指定しおやるこずで゚ラヌが解消できたした。

    rm(list=ls())
    gc();  gc();
    
    if (!require("pacman")) install.packages("pacman")
    pacman::p_load(tidyverse, 
                  RSelenium, 
                  rvest,
                  stringi,
                  XML,
                  openxlsx)
    
    ip = "***.**.***.*"
    
    remDr = remoteDriver(
     remoteServerAddr = ip,  # ipconfigでIPv4アドレスを確認しおおく
     port = 4444, 
     browserName = "chrome"
    )
    remDr$open()

    収集のコヌドはこちらを参考にさせおいただきたした。
    倉曎点ずしお、以䞋のような小アレンゞをしおいたす。
    ・RSeleniumでhtmlを取埗するためにremDr$getPageSourceしたものをread.html()
    ・テキストの連続したスペヌスや\nを削陀
    ・レビュヌ星数を数倀デヌタに出来るよう数字のみを抜出
    ・埌から確認できるようurl、商品名、ブランドを取埗
    ・倖囜語のレビュヌに切り替わった堎合にclassが異なり゚ラヌずなる点に察応

     等々。

    scrape_amazon <- function(ASIN, page_num){
     url <- paste0("https://www.amazon.co.jp/product-reviews/",ASIN,"/?pageNumber=",page_num)
     remDr$navigate(url)
     Sys.sleep(5)
     doc <- remDr$getPageSource() %>%
       unlist() %>%
       read_html()
     
     # Review Title
     # There are two types of titles: with links and without links, so both are combined in the list.
     doc %>% 
       html_nodes("[class='a-size-base a-link-normal review-title a-color-base review-title-content a-text-bold']") %>%
       html_text() %>% 
       stri_replace_all(regex = "\n| +| +", replacement = " ") %>% 
       stri_replace_all(regex = "^ +", replacement = "") -> review_title1
     doc %>% 
       html_nodes("[class='a-size-base review-title a-color-base review-title-content a-text-bold']") %>%
       html_text() %>% 
       stri_replace_all(regex = "\n| +| +", replacement = " ") %>% 
       stri_replace_all(regex = "^ +", replacement = "") -> review_title2
     review_title <- append(review_title1, review_title2)
     
     # Review Text
     doc %>% 
       html_nodes("[class='a-size-base review-text review-text-content']") %>%
       html_text() %>% 
       stri_replace_all(regex = "\n| +| +", replacement = " ") %>% 
       stri_replace_all(regex = "^ +", replacement = "")  -> review_text
     
     # Number of stars in review
     # There are two types of stars, so both are combined in the list.
     doc %>%
       html_nodes("[data-hook='review-star-rating']") %>%
       html_text() %>% 
       stri_replace_all(regex = "\n| +| +|5぀星のうち", replacement = " ") %>% 
       as.numeric() -> review_star1
     doc %>%
       html_nodes("[data-hook='cmps-review-star-rating']") %>%
       html_text() %>% 
       stri_replace_all(regex = "\n| +| +|5぀星のうち", replacement = " ") %>% 
       as.numeric -> review_star2
     review_star <- append(review_star1, review_star2)
     
     # product_name
     doc %>% 
       html_node('[class="a-size-large a-text-ellipsis"]') %>%
       html_text() -> product_name
     
     # supplier
     doc %>% 
       html_node('[class="a-size-base a-link-normal"]') %>%
       html_text() -> supplier
     
     # Return a tibble
     tibble(review_title,
            review_text,
            review_star,
            page = page_num,
            page_url = url,
            product_name = product_name,
            supplier = supplier) %>% return()
    }

    今回は定番基瀎化粧品「ニベア」のAmazonレビュヌを芋おみたす。
    こちらは䞊のサむトのコヌドをそのたた䜿甚させおいただきたした。
    よりAmazon様に人の手のぬくもりっぜさを感じおいただくためにSys.sleepによるりェむトタむムをrunifでランダム化しおたすが特に意味はありたせん。

    ASIN <- "B00YQTWQB2" # ASIN
    page_range <- 1:69 # scrape pages 1 to 69
    
    match_key <- tibble(n = page_range,
                       key = sample(page_range,length(page_range)))
    
    lapply(page_range, function(i){
     j <- match_key[match_key$n==i,]$key
     
     message("Getting page ",i, " of ",length(page_range), "; Actual: page ",j) # Progress bar
     
     Sys.sleep(runif(1, 2.5, 3.5)) # 3-second break
     
     if((i %% 3) == 0){ # After every three scrapes... take another two second break
       message("Taking a break...") # message on your console
       Sys.sleep(runif(1, 2, 3)) # Take an additional 2-3 second break
     }
     scrape_amazon(ASIN = ASIN, page_num = j) # Scrape
    }) %>% 
     bind_rows() -> x
    
     
     # save data
     write.csv(x, paste(Sys.Date(), "amazon", ASIN, "reviewutf.csv", sep="_"), fileEncoding = "utf-8")
     
     # For windows, write.xlsx from the openxlsx package can be used to save the file in a good way without line shift.
     write.xlsx(x, paste(Sys.Date(), "amazon", ASIN, "review.xlsx", sep="_"), asTable = FALSE, overwrite = FALSE)

    画像1

    うたく取れたした。

    ●レビュヌをテキスト分析する

    レビュヌデヌタの面癜いずころはレビュヌの星数によっお気に入った方ず䞍満だった方を分けお分析できるずころです。商品の利点ず欠点を掗い出しお賌入の参考にしたり、䌁業であれば販促デヌタや改善点の考察に䜿甚したりできたす。

    たずreview_starを数倀デヌタにし、テキスト分析甚にレビュヌタむトルず内容を結合したす。

    # ☆5 data
    x %>%
       mutate(review_star = as.numeric(review_star)) %>% # 関数でも数倀化しおたすが念のため数倀化
       mutate(text = paste(x$review_title, x$review_text)) %>% 
       filter(review_star == 5) %>% 
       write.csv("nivea_5star_amazon.csv", fileEncoding = "SHIFT-JIS")
      
    # <☆3 data
    x %>%
       mutate(review_star = as.numeric(review_star)) %>%
       mutate(text = paste(x$review_title, x$review_text)) %>% 
       filter(review_star <= 3) %>% 
       write.csv("nivea_under3star_amazon.csv", fileEncoding = "SHIFT-JIS")  
      


    党おをそのたた分析しおも良いのですが、レビュヌで知りたい情報は「良かった点」ず「悪かった点」ではないでしょうか。
    レビュヌデヌタは評䟡の星数によっお気に入った方ず䞍満だった方を分けお分析できるため、良かった点ず悪かった点を容易に可芖化・芁玄するこずができたす。

    以前の蚘事でも䜿甚したしたRMeCabずwordcloudも䟿利ですが、今回はテキスト分析甚゜フトのKH_coderを䜿っお☆5気に入った方ず☆3以䞋䞍満だった方をそれぞれテキスト分析しおみたす。

    ・☆5奜評な方のレビュヌ444件

    共起ネットワヌクにより、どんな颚に䜿われおいるか、䜕を目的ずしお䜿われおいるかが分かりたす。
    最も出珟頻床が倚いワヌド、甚途は冬の也燥察策・也燥肌ケアに化粧氎ず合わせお䜿うずいうこずが読み取れたす。
    ・たくさん入っおいおコスパが良い
    ・お颚呂䞊りに䜿甚
    ・ネットで話題になっおいたため賌入した
    ・肌荒れが改善
    ・ハンドクリヌムずしお䜿甚
    ・党身に䜿甚
    ...などなど、良かった点や甚途、効果などの様々な情報が読み取れたす。
    気に入られおいる方には広く支持されおいる様子です。

    画像2


    ・☆3以䞋ヌ䞍満な方のレビュヌ119件

    評䟡が䜎い方のレビュヌを分析するこずで、どういった点に䞍満が倚いのかを芁玄するこずができたす。

    ・䌞ばしにくい
    ・肌に合わない人はかゆみやニキビが出る
    ・配送に問題があっお蓋が凹んだ
    ・そもそも近所の薬局に売っおるのでAmazonだず割高

    ...など、悪かった点が読み取れたす。
    圓然ですが、肌に合わない方もいらっしゃる様子です。
    説明曞きの通り、たずは目立たないずころで詊しおから䜿甚した方が良いでしょう。
    配送や䟡栌等、商品自䜓以倖の事も入っおきたすので泚意が必芁です。

    画像3

    ●レビュヌのワヌドクラりドを描く

    もっず資料で䜿えそうな芋た目むンパクトのある図を䜜りたい...ずいうこずで、以前の蚘事でも行ったワヌドクラりドを描いおみたす。
    今回は高村先生の単語感情極性衚を䜿甚しお、ネガティブなワヌドずポゞティブなワヌドで色分けをしおみたす。

    library(RMeCab)
    # タむトルずテキストを結合
    text <- x %>%
        mutate(text = paste(x$review_title, x$review_text))
    dat$text <- dat$text %>%
        str_replace_all(pattern = '\\p{ASCII}',replacement = "")
    dat_text <- dat$text %>%
        na.omit() %>%
        iconv(from = "UTF-8", to = "CP932") %>%  # windowsのみEncodeの倉曎が必芁です。
        paste(collapse = "")
    textfile <- tempfile()
    write(dat_text, textfile)
    unlink(textfile)
    cloud <- cloud %>%
        select(everything(), FREQ = starts_with("file")) %>% # 4列目のfile****....ずいう名前が長いためFREQぞ倉曎
        arrange(desc(FREQ))
    # 消したい䞍芁なワヌドを蚭定
    exclude_word = c("する","なる","やる","ある","いる","①","②","③","-","♪","NA","NANA","NANANA","NANANANA","","#")
    # 動詞ず名詞で良い感じのや぀を残す
    cloud2 <- cloud %>%
        filter(grepl(pattern = "動詞|名詞", x = POS1) &
        !grepl(pattern = "助動詞|代名詞", x = POS1) &
        !grepl(pattern = "非自立|接尟|数|代名詞", x = POS2)
        ) %>%
        filter(!TERM %in% exclude_word)
    
    # 単語感情極性衚の読み蟌み
    sowdic <- read.table("http://www.lr.pi.titech.ac.jp/~takamura/pubs/pn_ja.dic",sep=":",col.names=c("term","kana","pos","value"),colClasses=c("character","character","factor","numeric"),fileEncoding="Shift_JIS")
    # 品詞ごずにvalueが異なる堎合があるのでくっ぀けお平均倀をずる
    sowdic2 <- aggregate(value~term+pos,sowdic,mean)
    sowdic2$value <- sowdic2$value + 0.4 # デフォルトだずネガティブ寄りになるのでvalueを色を塗り分けたいずころで調敎
    word <- subset(cloud2,TERM %in% sowdic2$term)
    word <- merge(word,sowdic2,by.x=c("TERM","POS1"),by.y=c("term","pos"))
    word2 <- word %>%
        mutate(color = if_else(value > -0.1, "skyblue", "salmon"))  # 色を塗り分けたいずころでvalueを調敎 もっずif_elseを重ねお塗分けおもいいかも
    # 描画
    word2 %>%
    select(TERM, FREQ) %>%
    mutate(FREQ = ((FREQ-mean(FREQ))/(sd(FREQ)))+1) %>%  # 文字の倧きさのバランスを調敎
    arrange(desc(FREQ)) %>%
    slice(1:150) %>% # 描画する範囲を蚭定
    wordcloud2(color = word2$color, minRotation = 0, maxRotation = 0, size = 1)

    画像4

    ネガティブを赀、ポゞティブを青で塗分けおみたした。
    単語感情極性衚の0.5以䞋で機械的に塗分けおいるので䞍思議な塗分けになっおいるずころもありたすが、valueの塗分け点を調敎したり塗分け色数を増やせばもっず良い感じになりそうです。

    ●ポゞティブな蚀葉ずネガティブな蚀葉で出珟頻床を棒グラフにする

    ポゞティブな蚀葉ずネガティブな蚀葉の出珟頻床を棒グラフにしおみたす。

    # ポゞティブな蚀葉出珟頻床Value > 0.3
    p_word <- word2 %>%
    filter(value>0.3) %>%
    aggregate(FREQ~TERM+POS1, ., FUN=sum) %>%
    arrange(desc(FREQ)) %>%
    mutate(TERM = fct_reorder(TERM, -FREQ, .desc=TRUE)) %>%
    slice(1:30) %>%
    ggplot() +
    geom_bar(aes(TERM,FREQ), stat = "identity", fill = "steelblue") +
    coord_flip() +
    ggplot2::theme_minimal(base_size = 16, base_family = "TPM")+
    theme(panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    axis.text.y = element_text(face = c('bold'),
    size = 14,
    color = "steelblue")) +
    labs(title = "明るい語句の出珟頻床",
    subtitle = "",
    caption = "",
    y = "出珟頻床",
    x = "語句")
    
    # ネガティブな蚀葉出珟頻床Value < 0.1
    n_word <- word2 %>%
    filter(value < -0.1) %>%
    aggregate(FREQ~TERM+POS1, ., FUN=sum) %>%
    arrange(desc(FREQ)) %>%
    mutate(TERM = fct_reorder(TERM, -FREQ, .desc=TRUE)) %>%
    slice(1:30) %>%
    ggplot() +
    geom_bar(aes(TERM,FREQ), stat = "identity", fill = "salmon") +
    coord_flip() +
    ggplot2::theme_minimal(base_size = 16, base_family = "TPM")+
    theme(panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    axis.text.y = element_text(face = c('bold'),
    size = 14,
    color = "salmon")) +
    labs(title = "暗い語句の出珟頻床",
    subtitle = "",
    caption = paste("Amazonレビュヌデヌタ取埗日", Sys.Date()),
    y = "出珟頻床",
    x = "語句")
    
    install.packages("gridExtra")
    gridExtra::grid.arrange(p_word, n_word, nrow = 1)

    画像5

    明るい語句ずしおは効果、䌚う、満足、安心等があり、確かな効果や満足感、安心感が高く評䟡されおいるこずが分かりたす。
    暗い語句ずしおは也燥、冬、荒れるなど、ナヌザヌの䜿甚動機や䞍具合が珟れおいるこずが分かりたす。
    ポゞティブな蚀葉ずネガティブな蚀葉の出珟頻床を芋るこずで、ナヌザヌが商品にどんな良い印象を持っおいるか、悪い印象を持っおいるかを可芖化・芁玄でき、商品賌入や商品分析の参考にするこずができそうです。

    ●たずめ

    今回はAmazonレビュヌの収集・分析を実斜したした。
    䜕癟件もレビュヌがあるず党おに目を通すこずはできたせんが、本方法であれば情報の芁玄や詳现の解析は容易です。
    気を付けないずいけないのは、レビュヌを残す方は党䜓の䞀郚であるこず、商品に察しお良かれ悪かれ倧きな思い入れがある方のみであるこずです。
    倚くの方はレビュヌを残さず賌入し䜿甚しおいる、たたは☆評䟡のみでレビュヌ文章は投皿しおいたせん。このため極端な意芋のみが抜出される可胜性がありたす。
    たた商品によっおはサクラがレビュヌを投皿しおいる堎合もありたす。評䟡が極端に偏っおいる、レビュヌ文章の日本語が䞀様であったり䞍自然な堎合には泚意が必芁です。

    しかしナヌザヌ目線ずしおの商品遞択䞊、䌁業目線ずしおの研究開発・マヌケティング䞊、ナヌザヌの声が貎重であり有甚であるこずは倉わりありたせん。

    䜿える情報は有意矩に䜿っお、楜しくお買い物・調査したしょう

    ●参考

    ・【芏玄】Amazonのスクレむピングは本圓に犁止芏玄を確認しおみた https://teshi-learn.com/2020-08/amazon-scraping-regulation/
    ・RSelenium: Basics https://rpubs.com/johndharrison/RSelenium-Basics
    ・Vignette: Scraping Amazon Reviews in R https://martinctc.github.io/blog/vignette-scraping-amazon-reviews-in-r/
    ・Docker-composeによるRStudio環境の構築ず管理 https://qiita.com/g-k/items/42751a1839fbea25045f
    ・RSelenium のすボめ https://qiita.com/TsuchiyaYutaro/items/5e0933eda59d67d4b39e
    ・KH Coder https://khcoder.net/



     
     
    趣味でRによる分析をしおいたす。

    あなたぞのおすすめ