R İle Web Sitesi Tarama ve Veri Kazıma İşlemi
Rcrawler Paketi ve Kullanımı
R ile ilgili bir önceki yazıda curl ile çekilen bir XML dosyası içeriğini okumuştuk. İlgili XML sürecini özellikle sitemap olarak ifade edilen, websitesi içeriğini (sayfalar, medyalar, vb.) arama motorlarına sunduğumuz protokol üzerinden örneklendirmiştim. Bu yazıda ise bir web sitesinin veya sadece belirli sayfaların nasıl taranabileceğine ve içeriğinden veri(leri) kazıyabileceğimizden bahsetmek istiyorum.
Crawling işlemi bir websitesi içeriğinin belirli bir amaç doğrultusunda bağlantılar aracılığı ile taranması işlemini ifade ediyor. Bu tarama işlemi meta data başta olmak üzere pek çok bilgiye erişim için gerçekleştirilebilir. Bu işlemi gerçekleştiren yazılımlar / botlar crawler ve/veya spider olarak ifade edilir. Arama motorlarının web siteleriyle ilgili bilgileri toplaması örnek olarak ele alınabilir. Veri Kazıma (Data Scraping) başlıklı yazıda da değindiğim üzere, scraping ise bir bilgi yığını içerisinden (sadece web sitesi olmak zorunda değil) ihtiyaç duyduğumuz bilginin ayıklanması sürecini ifade eder1.
R ve Crawling İşlemi
R programlama dili Rvest2, RCrawler3 ve scrapeR4 gibi popüler tarama ve kazıma paketlerini barındırmaktadır5. Bu paketlerin yanı sıra XML6 ve/veya XML27, jsonlite8, RJSONIO9, Selectr10, Httr11, RCurl12 ile de spesifik işlemler gerçekleştirmek mümkün. RSelenium13 ise tarama ve kazıma dışında sunduğu test özellikleri ile biraz farklı bir noktada değerlendirilebilir.
Örnek işlemler boyunca kullanacağım paket RCrawler olacak.
Rcrawler
Rcrawler, web sitelerinin / uygulamalarının taranması ve kurallar çerçevesinde belirtilmiş verilerin web, metin, içerik madenciliği amacıyla verilerin kazınması işlemlerinde kullanılan, popüler R paketlerinden biridir14 15 16. Yukarıda bahsi geçen örnekler arasında öne çıkan seçeneklerden biri olan Rcrawler ile rvest arasındaki farklılığa da kısaca değinmek gerekirse; rvest verinin spesifik bir sayfadan ve/veya seçiciler (selectors) aracılığı ile kazırken, Rcrawler bir kural belirlenmemişse bir web sitesinin tüm sayfalarını otomatik olarak dolaşıp (traverse) ayrıştırabilir (parse) ve ihtiyaç duyulan tüm verileri tek seferde çıkarabilir (extract)17 18 3.
install.packages("Rcrawler")
library(Rcrawler)
# Eğer "Error in makePSOCKcluster(names = spec, ...): Cluster setup failed." hatası alırsanız aşağıdaki satırı çalıştırabilirsiniz:
# parallel:::setDefaultClusterOptions(setup_strategy = "sequential")
## https://stackoverflow.com/questions/17966055/makecluster-function-in-r-snow-hangs-indefinitely
setwd("/Users/user/Desktop/scanning")
Rcrawler(Website = "https://domain.com")
Yukarıdaki satırlar itibariyle Website
aranmaya başlayacaktır. Herhangi bir URL, seçici ve/veya derinlik sınırı olmadığı için erişebildiği tüm bağlantılar üzerinden ilerleyecektir. Taramanın tamamlanmasının ardından tarama sonucu INDEX
adında bir değişkene list
tipinde eklenecektir. Ayrıca, setwd()
ile belirtilen dizine listedeki satırların karşılığı olan sayfaları HTML formatında yerleştirir. Yapılan taramalar sonucunda oluşturulan bu dizinlere ListProjects()
fonksiyonu ile ulaşmak mümkün.
[1] "domain.com-231149" "domain.com-231423" "domain.com-231727" "domain.com-232051" "domain.com-232102" "domain.com-232130" "domain.com-232131" "domain.com-232132"
Bu liste içeriğindeki HTML dosyalarına ise LoadHTMLFiles()
ile erişebiliriz.
pageData <- LoadHTMLFiles("domain.com-232132", type = "vector")
summary(pageData)
head(pageData, n = 1)
pageData
içeriğinin tamamını listelemenizi önermem. Ancak, fikir sahibi olmak için head
veya tail
ile bir kısmını inceleyebilirsiniz. Örneğin, bu site dahilinde yapılan tarama summary
ile de görüntülendiğinde 4320 kayıt olduğu görülüyor. Özellikle listeleme sayfalarının bu sayıda büyük bir etkisi mevcut.
Length | Class | Mode |
---|---|---|
4320 | character | character |
Rcrawler
tarama sürecinin tamamlanmasının ardından oluştulan INDEX
içeriğine baktığımızda ise aşağıdaki gibi bir tablo ile karşılaşırız.
View(head(INDEX, n = 2))
Id | Url | Stats | Level | OUT | IN | Http Resp | Content Type | Encoding | Accuracy |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | https://domain.com/ |
finished | 0 | 28 | 1 | 200 | text/html | UTF-8 |
2 | 2 | https://domain.com/about |
finished | 1 | 13 | 1 | 200 | text/html | UTF-8 |
Edindiğimiz bu veri üzerinden temel bazı veri tipi dönüştürme ve ardından veri kontrol işlemleri gerçekleştirelim.
INDEX$Id <- as.integer(INDEX$Id)
INDEX$Stats <- as.factor(INDEX$Stats)
INDEX$IN <- as.integer(INDEX$IN)
INDEX$OUT <- as.integer(INDEX$OUT)
INDEX$`Content Type`<-as.factor(INDEX$`Content Type`)
INDEX$`Http Resp`<-as.factor(INDEX$`Http Resp`)
INDEX$Encoding<-as.factor(INDEX$`Encoding`)
any(INDEX$`Http Resp` == "200")
any(is.na(INDEX$`Http Resp`))
Görüldüğü üzere, ilgili sayfa derinliği ve HTTP Status Code içerikleri gibi bilgiler bize sunulmakta. Elbette Rcrawler ile XPath tanımları yaparak taranan sayfalardan heading etiketleri, meta verileri, içerik gibi çeşitli bilgileri de ayıklayabiliriz.
Rcrawler(
Website = "https://domain.com",
no_cores = 4,
no_conn = 4,
ExtractXpathPat = c(
"//title",
"//h1",
"//link[@rel='canonical']/@href",
"/meta[@rel='robots']/@content",
"/link[@rel='alternate']/@hreflang",
"//body/@class"),
PatternsNames = c(
"title",
"h1",
"canonical",
"metarobots",
"hreflang",
"bodyclass"))
crawledData <- as.data.frame(do.call(rbind, DATA))
View(head(crawledData, n = 1))
Evet, görüldüğü üzere sayfa içeriğine dair istediğimiz bilgilere sahibiz. Bu sayede, heading ve/veya meta verileri eksik olan, içeriği yetersiz olan sayfaları ayıklayabilir ve bu içeriklerin geliştirilmesini sağlayabiliriz. Eğer heading etiketleri içerisinde span
, br
ve benzeri etiketler kullanıyorsanız büyük ihtimalle boşluklar da görüntüleyeceksiniz. Bu tür durumlarda, ilgili veri parçasını trimws()
ile düzenleyebilirsiniz.
Yukarıdaki örnek temelinde çeşitli iyileştirmeler yapıldığını varsayalım. Bu durumda tekrar sitenin tamamını taramak yerine ContentScraper()
ile sayfa temelinde işlemler gerçekleştirebilir ve vakitten tasarruf edebiliriz.
updatedPosts <- ContentScraper(
Url = "https://domain.com/post-1",
XpathPatterns = c("//title",
"//h1",
"//h2",
"//h3",
"//link[@rel='canonical']/@href",
"//meta[@name='description']/@content",
"//meta[@name='keywords']/@content",
"//link[@rel='stylesheet']/@hreflang"),
ManyPerPattern = TRUE)
Şimdilik işlemlerimiz bu kadar. Bir sonraki yazıda bir web sitesi içeriğini tarayıp elde ettiğimiz verileri sitemap oluşturmak amacıyla kullanacağız.
- Web Data Crawling vs Web Data Scraping Python ↩
- rvest helps you scrape (or harvest) data from web pages ↩
- Rcrawler: Web Crawler and Scraper ↩ ↩
- scrapeR: Tools for Scraping Data from HTML and XML Documents ↩
- tm.plugin.webmining: Retrieve Structured, Textual Data from Various Web Sources ↩
- XML: Tools for Parsing and Generating XML Within R and S-Plus ↩
- xml2: Parse XML ↩
- jsonlite: A Simple and Robust JSON Parser and Generator for R ↩
- RJSONIO: Serialize R Objects to JSON, JavaScript Object Notation ↩
- selectr: Translate CSS Selectors to XPath Expressions ↩
- httr: Tools for Working with URLs and HTTP ↩
- RCurl: General Network (HTTP/FTP/...) Client Interface for R ↩
- An R client for Selenium Remote WebDriver ↩
- Martin Schweinberger. (2021). Web Crawling and Scraping using R ↩
- Dániel Szabó. (2020). Web Crawling in R ↩
- Salim Khalil. (2019). R web scraper and crawler ↩
- François Joly. (2020). SEO Crawling & metadata extraction with R & RCrawler ↩
- Hiren Patel. (2018). An introduction to web scraping using R ↩