| Bytes | Lang | Time | Link |
|---|---|---|---|
| 045 | Wolfram Language | 170927T232858Z | Vitaliy |
| 186 | Python 3 + Requests + PIL | 170630T232742Z | LyricLy |
| nan | JavaScript + HTML | 170701T002346Z | Justin M |
| 042 | PHP | 170630T231224Z | Jared Me |
| 095 | PHP | 170630T170519Z | Евгений |
| 093 | Powershell | 161028T095738Z | colsw |
| 075 | Perl + curl + feh | 161027T171927Z | a spaghe |
| 274 | Python 2.7 | 161027T230409Z | Ioannes |
| 298 | R | 161028T081420Z | plannapu |
| 3103 | PowerShell v3+ 103 Bytes | 161027T165143Z | Matt |
| 440 | AutoIt | 161027T192642Z | user4264 |
Wolfram Language 45 bytes ( Mathematica )
Import["https://xkcd.com/"<>#,"Images"][[2]]&
Usage with number:
%@"1500"
Usage without number:
%@""
Python 3 + Requests + PIL, 192 186 bytes
from requests import*
import PIL.Image as f
from io import*
r=get("https://xkcd.com/%s/info.0.json"%input()).json()
f.open(BytesIO(get(r["img"],stream=1).content)).show()
print(r["alt"])
Opens up an image viewer (whichever is default on the system it's being run on) containing the comic, and posts the title text to the console.
JavaScript + HTML, 124 + 18 = 142 bytes
i=>fetch(`//crossorigin.me/http://xkcd.com/${i||""}/info.0.json`).then(r=>r.json()).then(d=>(A.innerHTML=d.alt,B.src=d.img))
<img id=B><p id=A>
Cross-origin solution thanks to Kaiido's answer here.
17 bytes (//crossorigin.me/) can be saved if the proxy required to connect to xkcd.com can be subtracted (meta post about this).
Test Snippet
f=
i=>fetch(`//crossorigin.me/http://xkcd.com/${i||""}/info.0.json`).then(r=>r.json()).then(d=>(A.innerHTML=d.alt,B.src=d.img))
<style>img{width:50%}</style><input id=I> <button onclick="f(I.value)">Run</button><br>
<img id=B><p id=A>
PHP, 42 bytes
<?=@file('http://xkcd.com/'.$_GET[i])[59];
Save to a file and fire it up in your web server of choice
PHP, 95 bytes
<?php echo str_replace("title=\"","/>",file_get_contents("https://xkcd.com/".$_GET["id"])); ?>
Save as main.php, run server
php -S localhost:8123
Powershell, 93 Bytes
93 Byte version to use local image viewer.
$n=(iwr xkcd.com/$args).images|?{$_.title};$n.title;iwr ("http:"+$n.src) -OutF x.jpg;ii x.*
Saved 2 bytes by removing needless doublequotes, then another lot by using ("http:"+$n.src) instead of "https://"+$n.src.trim("/") - since the img src comes with // already on it, and xkcd doesn't require https.
$n=(iwr xkcd.com/$args).images|?{$_.title};$n.title;saps ("http:"+$n.src)
$n=(iwr "xkcd.com/$args").images|?{$_.title};$n.title;saps ("https://"+$n.src.trim("/"))
extremely similar to Matts powershell answer, (should probably be a comment but low reputation)
Instead this opens a new tab/window in the default browser, and other things, saving some bytes.
iwr is an alias for Invoke-WebRequest
saps is an alias for Start-Process which opens 'it' in the default context.
Perl + curl + feh, 86 84 75 bytes
`curl xkcd.com/$_/`=~/<img src="(.*)" title="(.*?)"/;$_=$2;`feh "http:$1"`
Requires the -p switch. I have accounted for this in the byte count.
Python 2.7, 309 299 295 274 bytes
Full program. Definitely more golfable, but having read xkcd comics for so long I couldn't let this pass (who knows if this will be helpful in a future for easily browsing xkcd).
If no input is passed, gets current comic. If a valid comic number is passed as input then gets that comic. If an invalid input (not a number comic in the valid range) is passed, throws an error.
Any suggestions on how to reduce byte count are welcome! Will revisit (and add explanation) when I have more time.
-10 bytes thanks to @Dopapp
-21 bytes thanks to @Shebang
import urllib as u,re
from PIL import Image
h='http://';x='xkcd.com/'
o=u.URLopener()
t=u.urlopen(h+x+raw_input()).read()
c=sum([re.findall(r,t)for r in[h+'imgs.'+x+'c.*s/.*\.\w{1,3}','\.\w{1,3}" t.*e="(.*)" a']],[])
Image.open(o.retrieve(c[0],'1.png')[0]).show();print c[1]
R, 358 328 310 298 bytes
f=function(x){H="http:";p=paste0;library(XML);a=xpathSApply(htmlParse(p(H,'//xkcd.com/',x)),'//div/img',xmlAttrs)[[1]];download.file(p(H,a[1]),'a');I=`if`(grepl('png',a[1]),png::readPNG,jpeg::readJPEG)('a');d=dim(I)/100;quartz(,d[2],d[1]);par(mar=rep(0,4));frame();rasterImage(I,0,0,1,1);cat(a[2])}
With new lines and comments:
f=function(x){
H="http:"
p=paste0
library(XML) #Needed for xpathSApply, htmlParse and xmlAttrs
# The following line find the first img element and extract its attributes
a=xpathSApply(htmlParse(p(H,'//xkcd.com/',x)),'//div/img',xmlAttrs)[[1]]
download.file(p(H,a[1]),'a') #Download to a file called 'a'
I=`if`(grepl('png',a[1]),png::readPNG,jpeg::readJPEG)('a') #Check if png or jpeg and load the file accordingly
d=dim(I)/100 #convert dimension from pixel to inches (100 ppi).
quartz(,d[2],d[1]) #open a window of the correct dimension
par(mar=rep(0,4)) #Get rid of margins
frame() #Create empty plot
rasterImage(I,0,0,1,1) #Add png/jpeg to the plot
cat(a[2]) #Print title text to stdout
}
Screenshots of test cases:
PowerShell v3+ 110 99 107 103 Bytes
iwr($x=((iwr "xkcd.com/$args").images|?{$_.title})).src.Trim("/") -outf x.jpg;if($x){ii x.jpg;$x.title}
Thanks to Timmy for helping save some bytes by using inline assignments.
If no arguments are passed then $args is null and it will just get the current comic. Download the picture, by matching the one with alt text, into a file in the current running directory of the script. Then display it with the default viewer of jpg's. The alt text is then displayed to console. iwr is an alias for Invoke-WebRequest
If the number passed (or any invalid input for that matter) does not match the process fails with at least a 404 error.
iwr( # Request the comic image from XKCD
$x=((iwr "xkcd.com/$args").images| # Primary search to locate either the current image
# or one matching an argument passed
?{$_.title})) # Find the image with alt text
.src.Trim("/") # Using the images associated link and strip the leading slashes
-outf x.jpg # Output the image to the directory local to where the script was run
if($x){ # Test if the image acquisition was successful
ii x.jpg # Open the picture in with the default jpg viewer
$x.title # Display alt text to console
} # I'm a closing bracket.
AutoIt, 440 bytes
Yes, it's long, but it's stable.
#include<IE.au3>
#include<GDIPlus.au3>
Func _($0='')
_GDIPlus_Startup()
$1=_IECreate('xkcd.com/'&$0)
For $3 In $1.document.images
ExitLoop $3.title<>''
Next
$4=_GDIPlus_BitmapCreateFromMemory(InetRead($3.src),1)
$6=_GDIPlus_ImageGetDimension(_GDIPlus_BitmapCreateFromHBITMAP($4))
GUICreate(ToolTip($3.title),$6[0],$6[1])
GUICtrlSendMsg(GUICtrlCreatePic('',0,0,$6[0],$6[1]),370,0,$4)
_IEQuit($1)
GUISetState()
Do
Until GUIGetMsg()=-3
EndFunc
First of all, this doesn't use RegEx to scrape the site (because I have no time to test this on all comics), but rather uses the Internet Explorer API to iterate through the DOM's img tags until it finds one with a title text.
The binary stream is read from the image URL and rendered into a bitmap using GDIPlus. This is then displayed in a nice, auto-sized GUI with an actual tooltip to make it behave almost exactly like the website.
Here's a test case (_(859)):

)



