Proszę o przekazywanie wsparcia w ramach 1 proc. podatku dla Krzysia Bulczaka, największego bohatera, jakiego znam. KRS 0000037904 z dopiskiem 20374 Bulczak Krzysztof

Masowe pobieranie skanów z serwisu Szukaj w Archiwach

W pierwszych dniach października w założonym i zarządzanym przez Narodowe Archiwum Cyfrowe serwisie Szukajwarchiwach.pl dostępnych było ponad 34 mln skanów. Zbiory te pochodzą z państwowych instytucji archiwalnych i mogą być swobodnie wykorzystywane bez dodatkowych formalności, zgodnie z ustawą o ponownym wykorzystywaniu informacji sektora publicznego.

Pomimo tak bogatych zasobów, Szukaj w Archiwach nie publikuje interfejsu API do maszynowego wyszukiwania i pobierania skanów, planowana rozbudowa serwisu również nie uwzględnia opracowania takiego rozwiązania. Być może wśród użytkowników serwisu są tacy, którym zależy na sprawnym i szybkim pozyskiwaniu większej liczby skanów za jednym razem, choćby do dalszego opracowywania w ramach pracy badawczej czy w celu umieszczenia w zarządzanym przez siebie archiwum.

Kiedy nie ma API

Kiedy nie ma API, pozostaje jeszcze możliwość scrapowania zbiorów. Lubię ten sposób pracy z witrynami internetowymi, bo w jej trakcie bardzo dokładnie należy przyjrzeć się strukturze danych publikowanych na poszczególnych stronach i wymyślić sposób na ich wyodrębnienie z kodu HTML. Każda parsowana strona WWW staje się rodzajem bazy danych (zob. Lev Manovich, Database as Symbolic form, 1999), której zawartość jest dostępna za pomocą zapytań XPath. Udane wyodrębnienie danych ze strony WWW przypomina za każdym razem, że pod coraz bardziej wymyślnymi i dynamicznymi interfejsami graficznymi wciąż kryje się stara dokumentowa struktura drzewa znaczników.

Poniższy skrypt przetwarza podstrony wybranych jednostek archiwalnych z Szukaj w Archiwach i wyodrębnia adresy URL skanów dokumentów. Funkcja przyjmuje dwa argumenty: sygnaturę (np. 4/71/0/5/497) i opcję włączenia/wyłączenia pobierania; w przypadku uruchomienia funkcji bez pobierania plików zwróci ona do dowolnego wektora zestaw adresów URL skanów, łatwy do dalszego przetwarzania czy pobierania zewnętrznymi programami bez pośrednictwa R.

Problemy z certyfikatem SSL

Nieoczekiwanym problemem przy pisaniu tej funkcji był certyfikat SSL archiwum – możliwe rozwiązania zaproponowałem w liniach 17 oraz 59-62. Pliki skanów pobierane są wgetem z parametrem --no-check-certificate lub metodą z pakietu httr z wcześniej zdefiniowanym ignorowaniem certyfikatu. Metoda z użyciem httr jest jednak zdecydowanie mniej wydajna (pobieranie plików trwa bardzo długo).

Jak działa scraper? Wchodzi na stronę jednostki po podanej przez użytkownika sygnaturze, sprawdza ile stron prezentujących skany jest na niej dostępnych, po czym przetwarza każdą z nich (generując sobie w tym celu odpowiednie URLe) i gromadzi nazwy plików do pobrania.

# bulk download scans from szukajwarchiwach.pl
# id = signature
# download = FALSE (default) will download no files
# returns list of scan image URLS
# some troubles with ssl certificate

swa_get_scans <- function (id,download=FALSE) {
  
  library(httr)
  library(xml2)
  library(progress)
  
  # building base URL with id
  url <- paste0("https://szukajwarchiwach.pl/",id,"/#tabSkany")
  
  # how to avoid certificate errors with SSL
  httr::set_config(config(ssl_verifypeer = 0L))
  
  # parsing base URL
  u <- GET(url)
  u <- content(u, "text")
  u <- read_html(u, encoding = "UTF-8")
  u <- xml_find_all(u, "//div[@class='pagerBox']")
  u <- xml_find_all(u, '//a[position()>1]/text()')
  u <- as_list(u)
  u <- unlist(tail(u, n=1))
  
  # parsing u pages
  
  images <- character()
  
  for(i in 1:u){
    i <- paste0("https://szukajwarchiwach.pl/",id,"/str/1/",i,"/15#tabSkany")
    p <- GET(i)
    p <- content(p, "text")
    p <- read_html(p, encoding = "UTF-8")
    p <- xml_find_all(p, "//div[@class='searchListBg']")
    p <- xml_find_all(p, '//a[@class="fancy_scan_link"]/@href')
    p <- as_list(p)
    p <- unlist(p)
    images <- append(images, p, after=length(images))
  }
  
  # preparing proper urls for scan images
  
  images <- lapply(images, gsub, pattern="^/", replacement = "https://szukajwarchiwach.pl/")
  images <- lapply(images, gsub, pattern="medium", replacement = "img",fixed=TRUE)
  
  # if download
  
  if(download==TRUE){
    
    
    dir.create(gsub("/","-",id,fixed = TRUE))
    a <- 1
    pb <- progress_bar$new(total = length(images))
    
    for(i in images){
      # if you prefer using httr GET rather than download.file to overcome SSL errors (rather slow method)
      # GET(url=i, write_disk(paste0(gsub("/","-",id,fixed = TRUE),"/",a,".jpg")))
      # or if you want to use download.file with wget --no-check-certificate (faster)
      download.file(url=i, paste0(gsub("/","-",id,fixed = TRUE),"/",a,".jpg"), method="wget", quiet= TRUE, extra = "--no-check-certificate")
      a <- a + 1
      # progress bar
      pb$tick()
      Sys.sleep(sample(3:6,1))
    }
    
  }
  
  # at least return images urls
  return(unlist(images))
  
}

Taka funkcja przyda się przy dalszej pracy nad przetwarzaniem zasobów z Szukaj w Archiwach: masowo pobrane skany np. z tej jednostki można próbować automatycznie edytować i OCRować. Na pewno użyteczne byłoby też przygotowanie narzędzi do przeszukiwania zbiorów, eksportu metadanych i generowania ich zestawień statystycznych. Prace nad takim zestawem dla Szukaj w Archiwach blokują jednak (pośrednio) plany NAC: zapowiadana przebudowa serwisu może oznaczać radykalnie różną strukturę prezentowania zasobów, której stare scrapery nie będą mogły już przetwarzać.

Interesuje Cię maszynowe przetwarzanie zdigitalizowanych zbiorów dziedzictwa? Potrzebujesz własnego scrapera? Daj znać na m@wilkowski.org

Źródło grafiki: Projekt powiększenia istniejącej fabryki cyrkorii M. Blumenstocka, A. Goldfingera i Sz. Gajzlera w Lublinie, sygn. 35/403/0/5.5/1355, szukajwarchiwach.pl

GitHub: https://github.com/mw0000/R/blob/master/funkcje/swa_get_scans.R

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Akceptowane są wyłącznie komentarze merytoryczne. Każdy komentarz podlega moderacji.

Udostępnij na Twitterze | Udostępnij na Facebooku

Przeczytaj także