[問題類型]:使用R語言爬Instagram流程遇到問題
程式諮詢(我想用R 做某件事情,但是我遇到問題)
[軟體熟悉度]:
入門(寫過其他程式,只是對語法不熟悉)
[問題敘述]:
各位好
因為目前在學校修R相關的課教到爬蟲
爬一般的新聞網站、PTT、購物網站等的大概都可以了
最近想要嘗試爬爬看Instagram
最終目標是爬下特定hashtag以及特定帳戶的貼文
譬如說搜尋#植劇場 或是到金酒籃球隊(SBL的球隊公開帳號)
抓下貼文、按讚數、追蹤數等
最後再來看是否能夠做一些分析
現在嘗試過三種方法但都有遇到一定的問題
下方分別敘述
*方法一
使用instaR package
連結:https://github.com/pablobarbera/instaR
這個方法主要是利用instagram developer tool
連接官方的API
但因為instagram官方調整其政策
所以這個package裡面的一些function會被擋
像是searchInstagram() 函數爬 public content就失效了
在instagram developer tool 的 permission review處
(詳細步驟請參考 https://www.r-bloggers.com/analyze-instagram-with-r/)
若選擇自己的需求為
"I want to display hashtag content and public content on my website."
Instagram 的解答是:
"This use case is not supported. We do not approve the public_content
permission for one-off projects such as displaying hashtag based content on
your website. "
所以這個方法目前看來是不OK了
*方法二
使用RSelenium package
連結:https://github.com/ropensci/RSelenium
若需要操作教學的話可以參考
https://vectorf.github.io/2017/07/10/20170710-%E5%88%9D%E6%8E%A2RSelenium/
http://rpubs.com/bigbrotherchen/randseleniumpractice
我目前按照教學操作上沒有太大問題
小提醒一下開啟cmd輸入java...那串之後記得不要關掉cmd!!!
我的作法大致描述如下
# 載入package
library(RSelenium)
library(rvest)
library(tidyverse)
rm(list = ls())
options(stringsAsFactors = FALSE)
username = "這串打你的IG帳號" # <username here>
password = "這串打你的IG密碼" # <password here>
hashtag = "#你要搜尋的hashtag" # <hashtag here>
# 建立連線後開啟instagram登入網址
remDr <- remoteDriver(remoteServerAddr = "localhost", port = 4444,
browserName = "chrome")
remDr$open()
remDr$navigate("https://www.instagram.com/accounts/login/")
# 控制輸入帳號密碼後點選登入按鈕
webElem <- remDr$findElement(using = 'xpath', value =
"//div/input[@name='username']")
webElem$sendKeysToElement(list(username))
webElem2 <- remDr$findElement(using = 'xpath', value =
"//div/input[@name='password']")
webElem2$sendKeysToElement(list(password))
webElem3 <- remDr$findElement(using = 'xpath', value = "//span/button")
webElem3$clickElement()
# 在搜尋框裡面輸入hashtag後點選搜尋按鈕
webElem4 <- remDr$findElement(using = 'xpath', value =
"//div/input[@placeholder='搜尋']")
webElem4$sendKeysToElement(list(hashtag))
webElem5 <- remDr$findElement(using = 'xpath', value =
"//*[@id='react-root']/section/nav/div[2]/div/div/div[2]/div[2]/div[2]/div/a[1]")
webElem5$clickElement()
#(到這邊的時候就已經進入特定hashtag的所有貼文頁面了
# 控制網頁自動拉到網頁最下方
last_height = 0
repeat {
remDr$executeScript("window.scrollTo(0,document.body.scrollHeight);",
list(remDr$findElement("css", "body")))
Sys.sleep(2)
new_height = remDr$executeScript("return document.body.scrollHeight",
list(remDr$findElement("css", "body")))
if(unlist(last_height) == unlist(new_height)) {
break
} else {
last_height = new_height
}
}
#到這邊的時候會拉到所有貼文最底下
#之所以會這樣做是因為請教朋友的時候對方說
#這類網站叫做waterfall 不會一次讀完
#跟FB有點像往下拉才讀的到
# 想要用rvest package一般爬網頁的作法
remDr$getPageSource()[[1]] %>% read_html(encoding = "UTF-8")
#這邊就會遇到問題
#結果長這樣
#{xml_document}
#<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-tw" class="js logged-in
client-root">
#Error in nchar(desc) : invalid multibyte string, element 2
#上網查了一下Error in nchar(desc)跟invalid multibyte string
#但問題主要是跟編碼有關所以才會加入UTF-8
#可是還是沒有效果
#想要請問一下是否有人知道
#因為我不太熟html跟xpath所以爬得有點辛苦
*方法三
使用jsonlite package
# 載入package
library(rvest)
library(tidyverse)
library(jsonlite)
library(httr)
library(xml2)
#我先以#台啤18天 當作目標進去IG頁面
#其網址如下:
#https://www.instagram.com/explore/tags/台啤18天/?hl=zh-tw
#接下來我按照爬蟲教學常見的作法
#先按下檢查後點preserve log 還有clear(左上角紅點右邊的按鈕)
#圖請參考:
https://i.imgur.com/Pt6O5Gl.png
#接下來重新整理頁面後
#觀察XHR部分後發現?__a=1這個東西是要抓取的目標
# 用函數開始抓
url =
"https://www.instagram.com/explore/tags/%E5%8F%B0%E5%95%A418%E5%A4%A9/?__a=1"
res <- fromJSON(content(GET(url), "text"))
#這部分res出來之後有自己要的資料
#譬如說抓下來某一則貼文的內容在下方的程式碼裡面可以找到
res$graphql$hashtag$edge_hashtag_to_media$edges$node$edge_media_to_caption$edges[[20]]
#但這段程式碼裡面沒有包含所有的貼文僅有一部分而已
#所以往下拉之後繼續觀察XHR部分發現有一塊東西?query_hash是目標
#圖請參考
https://i.imgur.com/jUQLMtt.png
#試圖抓取其url之後利用函數但遇到問題了
url10 <-
"https://www.instagram.com/graphql/query/?query_hash=ded47faa9a1aaded10161a2ff32abb6b&variables=%7B%22tag_name%22%3A%22%E5%8F%B0%E5%95%A418%E5%A4%A9%22%2C%22first%22%3A1%2C%22after%22%3A%22AQBs_yhQbCXYxR7WgT2L598zGjRAT1iunnUIPbNxMQx8BbxZsm-S3YMyJK4bCyBRntcrLemDJqF_b_5Y9YlnQvUS7Iz34M6dWu8ONoX9_jJVaw%22%7D"
res10 <- fromJSON(content(GET(url10), "text"))
#遇到的error顯示
#Error: parse error: premature EOF
#
# (right here)