Code Image Image Downloader

20

OSTRZEŻENIE: Odpowiedzi mogą być przydatne dla niektórych golfistów kodowych.

W wielu wyzwaniach związanych z post zawiera obrazy, które muszą zostać zapisane w pliku, aby można było rozwiązać problem. Jest to szczególnie żmudne zadanie ręczne. My, programiści, nie powinniśmy być narażeni na takie znęcanie się. Twoim zadaniem jest automatyczne pobranie wszystkich obrazów zawartych w pytaniu Code Golf.SE.

Zasady

  • Twój program może łączyć się z dowolną częścią stackexchange.com, ale nie może łączyć się z żadnymi innymi domenami, z wyjątkiem lokalizacji obrazów (tj. Nie przejmuj się skracaczem adresów URL).
  • Liczba całkowita N jest podawana jako dane wejściowe, w wierszu poleceń lub stdin.
  • URL gwarantuje, że jest to prawidłowy link do pytania Code Golf.http://codegolf.stackexchange.com/questions/N
  • Każdy obraz wyświetlany w treści pytania N musi zostać zapisany w pliku na komputerze lokalnym. Każda z następujących lokalizacji jest dopuszczalna:
    • Bieżący katalog
    • Katalog wprowadzony przez użytkownika
  • Twój program nie może zapisywać plików innych niż obrazy w treści pytania (np. Awatary użytkowników lub obrazy zawarte w odpowiedziach).
  • Obrazy należy zapisać z tym samym rozszerzeniem pliku, co oryginał.

To jest - napisz najkrótszy program, jaki możesz.

Kryterium ważności dla odpowiedzi

Istnieją różne możliwe przypadki krawędzi z wieloma obrazami o tej samej nazwie, tekstem o tej samej nazwie co elementy HTML itp. Odpowiedź zostanie unieważniona tylko wtedy, gdy będzie można wykazać, że zakończy się niepowodzeniem w przypadku niektórych zmian pytania zadanego przed 10 stycznia 2015 r. .

feersum
źródło
Czy nazwy obrazów powinny być takie same, czy możemy zrobić jak 0.png, 1.png itp
stokastic 12.01.15
@stokastic Możesz nazwać część przed rozszerzeniem na cokolwiek chcesz (o ile nie użyjesz tej samej nazwy dwa razy, zastępując poprzedni plik).
feersum

Odpowiedzi:

10

Mathematica, 211 210 bajtów

i=Import;FileNameTake@#~Export~i@#&/@ImportString["body"/.("items"/.i["http://api.stackexchange.com/2.2/questions/"<>InputString[]<>"?site=codegolf&filter=!*Lgp.gEWHA6BNP.l","JSON"])[[1]],{"HTML","ImageLinks"}]

Nie golfowany:

i = Import;
FileNameTake@#~Export~i@# & /@ 
 ImportString[
  "body" /. (
    "items" /. 
      i["http://api.stackexchange.com/2.2/questions/" <> 
        InputString[] <> "?site=codegolf&filter=!*Lgp.gEWHA6BNP.l", 
       "JSON"]
  )[[1]], 
  {"HTML", "ImageLinks"}
 ]

To całkiem proste. Skonfigurowałem filtr dla interfejsu API StackExchange, który zwraca tylko treść pytania. Kod pobiera informacje o pytaniach z tym filtrem i analizuje je jako JSON. Wybieram odpowiedni element (treść) i używam go ImportStringdo parsowania kodu HTML i odfiltrowania wszystkich adresów URL obrazów. FileNameTake@#~Export~Import@#następnie pobiera każdy obraz i zapisuje go w bieżącym katalogu roboczym o tej samej nazwie pliku, co w adresie URL.

Możesz znaleźć bieżący katalog roboczy za pomocą Directory[].

Zasadniczo istnieje znacznie krótsza wersja, ponieważ ImportStringmożna pobrać wszystkie pliki od razu, zamiast podawać mi adresy URL. Ale potem tracę informacje o oryginalnym typie pliku (ponieważ są one konwertowane na Imageobiekty po pobraniu), więc mogę zapisać je wszystkie jako ten sam typ (powiedzmy PNG).

Martin Ender
źródło
8

JavaScript - 149 161 bajtów

$.get("http://codegolf.stackexchange.com/q/"+prompt(),function(e){$(".post-text:first img",e).each(function(e,t){$('<a href="'+t.src+'"download>')[0].click()})})

z białymi znakami

$.get('http://codegolf.stackexchange.com/q/' + prompt(), function(d) {
  $('.post-text:first img',d).each(function(i,e){
   $('<a href="' + e.src + '"download>')[0].click();
  })
})

skrypt musi zostać uruchomiony z witryny stackexchange do działania. Domyślnie zostanie wyświetlona bieżąca strona, jeśli w pytaniu nie zostanie podany numer pytania

Profesor Allman
źródło
1
Jak wspomniano powyżej @doorknob, możesz trochę zaoszczędzić, zamieniając q na pytanie. A jeśli nie masz nic przeciwko umieszczeniu wszystkich zdjęć w postach na stronie, możesz to zrobić $('[src*="imgur"]',d). Podoba mi się, że można to uruchomić w konsoli - natychmiastowa satysfakcja.
Josiah
1
questionsmożna skrócić q, ale powinna zawierać codegolf.stackexchange.comczęść zamiast polegać na byciu na tej stronie. @Josiah można umieszczać zdjęcia z innych domen we wpisach.
feersum
1
Selektor #question .post-text imgmożna skrócić do .post-text:first imglub .post-text:eq(0) img.
cPu1
5

Python 2 - 241 bajtów

Całkiem proste, prawdopodobnie można dalej grać w golfa. Przeszukuję witrynę w celu znalezienia wszystkich wystąpień img src=między pierwszym wystąpieniem post-texta /divnastępującym bezpośrednio po nim. Każdy adres URL obrazu jest następnie odczytywany i zapisywany w katalogu roboczym.

import string,sys,urllib,re;o=string.find;u=urllib.urlopen
r=u("http://codegolf.stackexchange.com/q/"+sys.argv[1]).read()
i=o(r,"post-text")
for p in re.findall(r'img src="([^"]*)',r[i:o(r,"/div",i)]):f=open(p[-9:],"wb");f.write(u(p).read())
stokastic
źródło
Nazwy plików są zachowywane w stanie, w jakim się znajdują - nazwa jest traktowana jako ostatnie 9 bajtów ( [-9:]) adresu URL obrazu, który powinien zawierać jej 5 znaków i a .pnglub .jpgitd. Odciąga bajty nazwy pliku, jeśli rozszerzenie jest dłuższe niż 3 znaki .
stokastic
Co jeśli nazwa pliku jest krótsza niż 9 bajtów? Czy nie zawierałoby ukośnika w nazwie pliku?
Martin Ender
możesz zapisać 2 bajty, tworząc forpętlę jedną linię. for p re.findall(...):f=open(...);f.write(...)
undergroundmonorail
@mar Nie sądzę, że nazwa pliku może mieć mniej niż 9 bajtów, ale mogę się mylić
undergroundmonorail
@ MartinBüttner Myślę, że 9 bajtów jest rozsądnym założeniem, ale mogę je zmienić, jeśli uważasz, że powinienem. Za to, co jest warte - użycie tylko 6 lub 7 bajtów prawdopodobnie wystarcza i nadal prawie gwarantuje odrębne nazwy plików.
stokastic
2

Mathematica, 195

x=XMLElement;c=Cases;i=Import;l=Infinity;FileNameTake@#~Export~i@#&/@(((c[#,x["img",{"src"->e_,_},___]:>e,l]&)@*(c[#,x[_,{__,"id"->"question",__},e_]:>e,l]&)@*(i[#,"XMLObject"] &))@InputString[])

To eksportuje obrazy w taki sam sposób, jak Martin zrobił w swoim rozwiązaniu Mathematica, przeczytaj jego odpowiedź, aby uzyskać więcej informacji na ten temat. To podejście bardzo różni się od jego, zamiast analizować wynik z interfejsu API, analizuję stronę HTML bezpośrednio. A raczej analizuję symboliczny XML, który Mathematica może wygenerować z HTML.


źródło
1

Python 2 - 398 342 334 bajty

Program pobiera stronę SE, wypakowuje część pocztową (element div post-tekstowy), wyszukuje adresy URL zakończone rozszerzeniem obrazu i pobiera je. Obrazy są zapisywane jak img<n>.<ext>w bieżącym katalogu.

import urllib2 as u,re,sys
z=u.urlopen;i=1
p=z('http://codegolf.stackexchange.com/q/'+sys.argv[1]).read()
s=re.search(r'ss="po(.+?)/di',p,16).group(1)
for L in re.findall('"(h.+?://.*?)"',s):
 b=L.rsplit('.',1)
 if len(b)==2 and b[1].lower() in 'jpg jpeg png gif bmp'.split():
  open('img%u.%s'%(i,b[1]),'wb').write(z(L).read());i+=1

Ten program pobierze również obrazy dostarczone jako łącze, a nie tylko obrazy osadzone. Nadając każdemu obrazowi unikalną nazwę pliku, można również uniknąć konfliktów nazw.

Logic Knight
źródło
2
Można zapisać 8 znaków zastępując questionsz q(w adresie URL).
Klamka
W pytaniu 43274 widzę tylko 11 zdjęć, ale 21 zostało pobranych.
feersum
Mój program pobiera 10 obrazów w wysokiej rozdzielczości, a także 10 miniatur. Nie jestem pewien, czy inne wpisy pobierają wersje w wysokiej rozdzielczości.
Logic Knight
@Doorknob - dzięki. Tęsknie za tym. Będę potrzebował znacznie więcej, aby złapać innych facetów.
Logic Knight
1
@CarpetPython, chociaż jest to prawdopodobnie bardziej przydatne ... celem specyfikacji było pobranie tylko widocznych obrazów.
feersum
1

Bash - 86 bajtów

wget -r -l1 -np -Ajpg,jpeg,png,bmp,gif http://codegolf.stackexchange.com/questions/$1

Nic się nie naprawi. -npzapobiega wchodzeniu wget do wyższych katalogów (User Imgs) -Atylko pobiera pliki z rozszerzeniem pasującym do przedstawionej listy. -rto rekurencyjne pobieranie. -lzapobiega zbyt głębokiemu wgetowi. $1to pytanie do uchwycenia.

HSchmale
źródło
1
Czy jest coś konkretnego, co muszę zrobić, aby to zadziałało? Próbowałem na kilku pytaniach, ale bez skutku. Wyjście tutaj .
Geobits
1
Myślę, że możesz zapisać 8 znaków, zastępując questionsje qw adresie URL.
Timtech
1

Node.js, 251 247 bajtów

r=require,g=r('request'),g('http://codegolf.stackexchange.com/q/'+process.argv[2],function(_,_,b){r('cheerio').load(b)('#question .post-text img').each(function(i,a){s=a.attribs.src,g(s).pipe(r('fs').createWriteStream(i+r('path').basename(s)))})})

Używa requestdo tworzenia HTTP GETi cheeriodo analizowania HTML. Kolizje nazw są rozwiązywane przez dodanie indeksu bieżącego obrazu do nazwy basenowej adresu URL pliku. Obrazy są zapisywane w tym samym katalogu, co bieżący plik.

cPu1
źródło
1

Lua, 200 bajtów

r=require'socket.http'.request r('http://codegolf.stackexchange.com/questions/'.. ...):gsub('post.text(.-)div',function(p)p:gsub('src="(.-)"',function(i)io.open(i:sub(-9),'wb'):write((r(i)))end)end)

Akceptuje liczbę jako argument wiersza polecenia.

Zakłada, że ​​dowolny src=atrybut będzie dla imgtagu, ponieważ są to jedyne tagi zsrc atrybutami, na które pozwala wymiana stosów (prawda?).

Zwróć również uwagę na .. .... Jestem z tego szczególnie dumny.

thenumbernine
źródło