Multifile crash
Tried to test multifile mode and encountered such error:

`Traceback (most recent call last):
  File "src/scripts/ccget", line 193, in <module>
    ccget()
  File "src/scripts/ccget", line 156, in ccget
    data = ccread(filename, **kwargs)
  File "/Users/invalidpointer/anaconda/envs/cclib-test/lib/python3.5/site-packages/cclib/io/ccio.py", line 112, in ccread
    log = ccopen(source, *args, **kargs)
  File "/Users/invalidpointer/anaconda/envs/cclib-test/lib/python3.5/site-packages/cclib/io/ccio.py", line 190, in ccopen
    inputfile.seek(0, 0)
AttributeError: 'FileInput' object has no attribute 'seek'`

I think it happens because in case of multiple files "openlogfile" function returns FileInput object which doesn't have "seek" method.
diff --git a/src/cclib/io/__init__.py b/src/cclib/io/__init__.py
index 8aa6e4e0..0c08c6fa 100644
--- a/src/cclib/io/__init__.py
+++ b/src/cclib/io/__init__.py
@@ -16,7 +16,8 @@ from .cjsonreader import CJSON as CJSONReader
 #   from cclib.io import ccopen
 #   from cclib.io import ccread
 #   from cclib.io import ccwrite
+#   from cclib.io import URL_PATTERN
 from .ccio import ccopen
 from .ccio import ccread
 from .ccio import ccwrite
-
+from .ccio import URL_PATTERN
diff --git a/src/cclib/io/ccio.py b/src/cclib/io/ccio.py
index 18eccfb2..d8424fcc 100644
--- a/src/cclib/io/ccio.py
+++ b/src/cclib/io/ccio.py
@@ -13,14 +13,22 @@ from __future__ import print_function
 import io
 import os
 import sys
+import re
+from tempfile import NamedTemporaryFile
+import atexit
 
 # Python 2->3 changes the default file object hierarchy.
 if sys.version_info[0] == 2:
     fileclass = file
+
+    from urllib2 import urlopen, URLError
 else:
     import io
     fileclass = io.IOBase
 
+    from urllib.request import urlopen
+    from urllib.error import URLError
+
 from ..parser import logfileparser
 from ..parser import data
 
@@ -49,6 +57,18 @@ except ImportError:
     _has_cclib2openbabel = False
 
 
+# Regular expression for validating URLs
+URL_PATTERN = re.compile(
+
+    r'^(?:http|ftp)s?://'  # http:// or https://
+    r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
+    r'localhost|'  # localhost...
+    r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
+    r'(?::\d+)?'  # optional port
+    r'(?:/?|[/?]\S+)$', re.IGNORECASE
+
+)
+
 # Parser choice is triggered by certain phrases occuring the logfile. Where these
 # strings are unique, we can set the parser and break. In other cases, the situation
 # is a little but more complicated. Here are the exceptions:
@@ -104,7 +124,8 @@ def ccread(source, *args, **kargs):
     the appropriate bridge such as OpenBabel.
 
     Inputs:
-        source - a single logfile, a list of logfiles, or an input stream
+        source - a single logfile, a list of logfiles, or an input stream.
+        Also URLs to log files are supported.
     Returns:
         a ccData object containing cclib data attributes
     """
@@ -129,7 +150,8 @@ def ccopen(source, *args, **kargs):
     """Guess the identity of a particular log file and return an instance of it.
 
     Inputs:
-      source - a single logfile, a list of logfiles, or an input stream
+      source - a single logfile, a list of logfiles, or an input stream.
+      Also URLs to log files are supported.
 
     Returns:
       one of ADF, DALTON, GAMESS, GAMESS UK, Gaussian, Jaguar, Molpro, MOPAC,
@@ -140,17 +162,57 @@ def ccopen(source, *args, **kargs):
     inputfile = None
     is_stream = False
 
+    # Check if source is a link or contains links. Retrieve their content.
     # Try to open the logfile(s), using openlogfile, if the source is a string (filename)
     # or list of filenames. If it can be read, assume it is an open file object/stream.
     is_string = isinstance(source, str)
+    is_url = True if is_string and URL_PATTERN.match(source) else False
     is_listofstrings = isinstance(source, list) and all([isinstance(s, str) for s in source])
     if is_string or is_listofstrings:
-        try:
-            inputfile = logfileparser.openlogfile(source)
-        except IOError as error:
-            if not kargs.get('quiet', False):
-                (errno, strerror) = error.args
-            return None
+        # Process links from list (download contents into temporary location)
+        if is_listofstrings:
+            filelist = []
+            for filename in source:
+                if not URL_PATTERN.match(filename):
+                    filelist.append(filename)
+                else:
+                    try:
+                        response = urlopen(filename)
+                        tfile = NamedTemporaryFile(delete=False)
+                        tfile.write(response.read())
+                        # Close the file because Windows won't let open it second time
+                        tfile.close()
+                        filelist.append(tfile.name)
+                        # Delete temporary file when the program finishes
+                        atexit.register(os.remove, tfile.name)
+                    except (ValueError, URLError) as error:
+                        if not kargs.get('quiet', False):
+                            (errno, strerror) = error.args
+                        return None
+            source = filelist
+
+        if not is_url:
+            try:
+                inputfile = logfileparser.openlogfile(source)
+            except IOError as error:
+                if not kargs.get('quiet', False):
+                    (errno, strerror) = error.args
+                return None
+        else:
+            try:
+                response = urlopen(source)
+                is_stream = True
+
+                # Retrieve filename from URL if possible
+                filename = re.findall("\w+\.\w+", source.split('/')[-1])
+                filename = filename[0] if filename else ""
+
+                inputfile = logfileparser.openlogfile(filename, object=response.read())
+            except (ValueError, URLError) as error:
+                if not kargs.get('quiet', False):
+                    (errno, strerror) = error.args
+                return None
+
     elif hasattr(source, "read"):
         inputfile = source
         is_stream = True
@@ -168,9 +230,9 @@ def ccopen(source, *args, **kargs):
         except (AttributeError, IOError):
             contents = inputfile.read()
             try:
-              inputfile = io.StringIO(contents)
+                inputfile = io.StringIO(contents)
             except:
-              inputfile = io.StringIO(unicode(contents))
+                inputfile = io.StringIO(unicode(contents))
             inputfile.seek(0, 0)
 
     # Proceed to return an instance of the logfile parser only if the filetype
diff --git a/src/cclib/parser/logfileparser.py b/src/cclib/parser/logfileparser.py
index e6162fd7..ec8dd4d5 100644
--- a/src/cclib/parser/logfileparser.py
+++ b/src/cclib/parser/logfileparser.py
@@ -125,10 +125,11 @@ class FileWrapper(object):
             self.pos = self.size
 
 
-def openlogfile(filename):
-    """Return a file object given a filename.
+def openlogfile(filename, object=None):
+    """Return a file object given a filename or if object specified decompresses it
+    if needed and wrap it up.
 
-    Given the filename of a log file or a gzipped, zipped, or bzipped
+    Given the filename or file object of a log file or a gzipped, zipped, or bzipped
     log file, this function returns a file-like object.
 
     Given a list of filenames, this function returns a FileInput object,
@@ -141,20 +142,22 @@ def openlogfile(filename):
         extension = os.path.splitext(filename)[1]
 
         if extension == ".gz":
-            fileobject = myGzipFile(filename, "r")
+            fileobject = myGzipFile(filename, "r", fileobj=object)
 
         elif extension == ".zip":
-            zip = zipfile.ZipFile(filename, "r")
+            zip = zipfile.ZipFile(object, "r") if object else zipfile.ZipFile(filename, "r")
             assert len(zip.namelist()) == 1, "ERROR: Zip file contains more than 1 file"
             fileobject = io.StringIO(zip.read(zip.namelist()[0]).decode("ascii", "ignore"))
 
         elif extension in ['.bz', '.bz2']:
             # Module 'bz2' is not always importable.
             assert bz2 is not None, "ERROR: module bz2 cannot be imported"
-            fileobject = myBZ2File(filename, "r")
+            fileobject = myBZ2File(object, "r") if object else myBZ2File(filename, "r")
 
         else:
-            fileobject = FileWrapper(io.open(filename, "r", errors='ignore'))
+            # Assuming that object is text file encoded in utf-8
+            fileobject = io.StringIO(object.decode('utf-8')) if object \
+                    else FileWrapper(io.open(filename, "r", errors='ignore'))
 
         return fileobject
 
diff --git a/src/scripts/ccget b/src/scripts/ccget
index 76afe15d..c7900ba8 100644
--- a/src/scripts/ccget
+++ b/src/scripts/ccget
@@ -18,7 +18,7 @@ import os.path
 import sys
 
 from cclib.parser import ccData
-from cclib.io import ccread
+from cclib.io import ccread, URL_PATTERN
 
 
 MSG_USAGE = """\
@@ -90,7 +90,7 @@ def ccget():
         print(MSG_USAGE)
         sys.exit(1)
 
-    # Figure out which are the attribute names and which are the filenames.
+    # Figure out which are the attribute names and which are the filenames or links.
     # Note that in Linux, the shell expands wild cards, but not so in Windows,
     # so try to do that here using glob.
     attrnames = []
@@ -98,7 +98,7 @@ def ccget():
     for arg in arglist:
         if arg in ccData._attrlist:
             attrnames.append(arg)
-        elif os.path.isfile(arg):
+        elif URL_PATTERN.match(arg) or os.path.isfile(arg):
             filenames.append(arg)
         else:
             wildcardmatches = glob.glob(arg)
diff --git a/test/io/testccio.py b/test/io/testccio.py
index f6c1a06d..cc179ab5 100644
--- a/test/io/testccio.py
+++ b/test/io/testccio.py
@@ -14,6 +14,11 @@ import unittest
 import cclib
 
 
+__filedir__ = os.path.dirname(__file__)
+__filepath__ = os.path.realpath(__filedir__)
+__datadir__ = os.path.join(__filepath__, "..", "..")
+
+
 class guess_fileypeTest(unittest.TestCase):
 
     def setUp(self):
@@ -80,6 +85,26 @@ class ccopenTest(unittest.TestCase):
         with tempfile.NamedTemporaryFile() as tf:
             self.assertIsInstance(self.ccopen(tf.name, cjson=True), cclib.io.cjsonreader.CJSON)
 
+    def test_url_io(self):
+        """Does the function works with URLs such good as with filenames?"""
+        fpath = os.path.join(__datadir__, "data")
+        base_url = "https://raw.githubusercontent.com/cclib/cclib/master/data/"
+        filenames = ["DALTON/basicDALTON-2013/dvb_td.out", "Molpro/basicMolpro2012/h2o_mp2.out"]
+        for fname in filenames:
+            self.assertEqual(self.ccopen(os.path.join(fpath, fname), quiet=True).parse().getattributes(tolists=True),
+                             self.ccopen(base_url + fname, quiet=True).parse().getattributes(tolists=True))
+
+    def test_multi_url_io(self):
+        """Does the function works with multiple URLs such good as with multiple filenames?"""
+        fpath = os.path.join(__datadir__, "data")
+        base_url = "https://raw.githubusercontent.com/cclib/cclib/master/data/"
+        filenames = ["Molpro/basicMolpro2012/dvb_gopt.log", "Molpro/basicMolpro2012/dvb_gopt.out"]
+        self.assertEqual(
+            self.ccopen([os.path.join(fpath, fname) for fname in filenames], quiet=True)
+                .parse().getattributes(tolists=True),
+            self.ccopen([base_url + fname for fname in filenames], quiet=True)
+                .parse().getattributes(tolists=True))
+
     # This should also work if cjsonreader supported streams.
     #def test_cjson(self):
     #    """Do we get a CJSON object then keyword argument used?"""
['test/io/testccio.py', 'src/cclib/parser/logfileparser.py', 'src/scripts/ccget', 'src/cclib/io/ccio.py', 'src/cclib/io/__init__.py']