[Question]
  [
xkcd is everyone's favorite webcomic, and you will be writing a program that will bring a little bit more humor to us all.  
Your objective in this challenge is to write a program which will take a number as input and display that xkcd and its title-text (mousover text). 
## Input
Your program will take a positive integer as input (not necessarily one for which there exists a valid comic) and display that xkcd: for example, an input of 1500 should display the comic "Upside-Down Map" at xkcd.com/1500, and then either print its title-text to the console or display it with the image.
[![Due to their proximity across the channel, there's long been tension between North Korea and the United Kingdom of Great Britain and Southern Ireland.](https://i.stack.imgur.com/LpNQf.png)](https://i.stack.imgur.com/LpNQf.png)
`Due to their proximity across the channel, there's long been tension between North Korea and the United Kingdom of Great Britain and Southern Ireland.`
Test case 2, for n=859:
[![Brains aside, I wonder how many poorly-written xkcd.com-parsing scripts will break on this title (or ;;"''{<<[' this mouseover text."](https://i.stack.imgur.com/ItL7a.png)](https://i.stack.imgur.com/ItL7a.png)
`Brains aside, I wonder how many poorly-written xkcd.com-parsing scripts will break on this title (or ;;"''{<<[' this mouseover text."`
Your program should also be able to function without any input, and perform the same task for the most recent xkcd found at xkcd.com, and it should always display the most recent one even when a new one goes up.
You do not have to get the image directly from xkcd.com, you can use another database as long as it is up-to-date and already existed before this challenge went up. URL shortners, that is, urls with no purpose other than redirecting to somewhere else, are not allowed.
You may display the image in any way you chose, including in a browser. You may ***not***, however, directly display part of another page in an iframe or similar. CLARIFICATION: **you cannot open a preexisting webpage, if you wish to use the browser you have to create a new page**. You must also actually display an image - outputting an image file is not allowed.
You can handle the case that there isn't an image for a particular comic (e.g. it is interactive or the program was passed a number greater than the amount of comics that have been released) in any reasonable way you wish, including throwing an exception, or printing out an at least single-character string, as long as it somehow signifies to the user that there isn't an image for that input.
You can only display an image and output its title-text, or output an error message for an invalid comic. Other output is not allowed.
This is a [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'") challenge, so the fewest bytes wins.
  
[Answer]
# 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.
[Answer]
## 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.
```
[Answer]
## [AutoIt](http://autoitscript.com), 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)`):
![](https://i.stack.imgur.com/IRgTc.png)
)
[Answer]
## 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.
[Answer]
# 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:
for x=1500:
[![for x=1500 (png)](https://i.stack.imgur.com/FK5Qj.png)](https://i.stack.imgur.com/FK5Qj.png)
for x empty:  
[![for x=''](https://i.stack.imgur.com/JXYwL.png)](https://i.stack.imgur.com/JXYwL.png)
case when picture is a jpeg:  
[![for x=10 (jpeg)](https://i.stack.imgur.com/XjgcE.png)](https://i.stack.imgur.com/XjgcE.png)
x=859:  
[![x=859](https://i.stack.imgur.com/f6V2Z.png)](https://i.stack.imgur.com/f6V2Z.png)
[Answer]
## 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
```
Open <http://localhost:8123/main.php?id=1500>
[Answer]
## 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]
```
[Answer]
# PHP, 42 bytes
```
<?=@file('http://xkcd.com/'.$_GET[i])[59];
```
Save to a file and fire it up in your web server of choice
[Answer]
# [Wolfram Language](http://reference.wolfram.com/language/) 45 bytes ( Mathematica )
```
Import["https://xkcd.com/"<>#,"Images"][[2]]&
```
Usage with number:
```
%@"1500"
```
Usage without number:
```
%@""
```
[Answer]
# 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](https://codegolf.stackexchange.com/questions/125715/lazy-click-and-drag/125759#125759).
17 bytes (`//crossorigin.me/`) can be saved if the proxy required to connect to xkcd.com can be subtracted ([meta post about this](https://codegolf.meta.stackexchange.com/questions/12846/should-proxy-usage-be-included-in-byte-counts/)).
## 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>
```
[Answer]
# 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. 
]