text: import os
  import re
  import types
  import urllib.parse
  import calendar
  import magic
  import datetime
  import sys
  import calendar
  import logging
  
  from PyPDF2 import PdfFileReader
  from xml.parsers.expat import ExpatError
  from xml.dom import minidom, Node
  from bs4 import BeautifulSoup, NavigableString, Tag
  from functools import reduce
  
  def parse_xml(xmlpage):
      try: 
          d = minidom.parseString(xmlpage)
      except ExpatError:
          d = None
      return d
  
  def get_node_value(xmlNodes):
      value = [] 
      ignoreValues = ['\n']
      for node in xmlNodes:
          if node.nodeType == Node.TEXT_NODE:
              if node.data not in ignoreValues:
                  value.append(node.data)
      return ''.join(value)
  
  def remove_spaces(x):
      x, n = re.subn('\s+', ' ', x)
      return x.strip()
  
  def check_next_page(tr, pagenum):
      links    = tr.findAll('a')
  
      if len(links) <= 0:
          return False, None
  
      for link in links:
          contents = get_tag_contents(link)
          if not contents:
              continue
          contents = contents.strip()
          if  not re.match('[\d.]+$', contents):
              return False, None
  
      pageblock = True
      nextlink  = None
  
      for link in links:
          contents = get_tag_contents(link)
          try:
              val = int(contents)
          except ValueError:
              continue
  
          if val == pagenum + 1 and link.get('href'):
              nextlink = {'href': link.get('href'), 'title': '%d' % val}
              break
  
      return pageblock, nextlink
  
  def month_to_num(month):
      month = month.lower()
      if month in ['frbruary', 'februay']:
          month = 'february'
  
      count = 0
      for mth in calendar.month_name:
          if mth.lower() == month:
              return count
          count += 1
  
      count = 0
      for mth in calendar.month_abbr:
          if mth.lower() == month:
              return count
          count += 1
  
      return None
  
  def to_dateobj(x):
      reobj = re.search('(?P<day>\d+)-(?P<month>jan|feb|mar|apr|may|jun|jul|aug|sep|aug|sep|oct|nov|dec)-(?P<year>\d+)', x, re.IGNORECASE)
      if reobj:
          groupdict = reobj.groupdict()
          month = month_to_num(groupdict['month'])
          day   = int(groupdict['day'])
          year  = int(groupdict['year'])
          return datetime.date(year, month, day)
  
      return None    
  
  def get_month_num(month, monthnames):
      i = 0
      month = month.lower()
      for m in monthnames:
          if m.lower() == month:
              return i
          i += 1
      return -1
              
  def parse_datestr(datestr):
      reobj = re.search('(?P<day>\d+)\s*(?P<month>\w+)\s*(?P<year>\d+)', datestr)
      if reobj:
          groupdict = reobj.groupdict()
          month_num = get_month_num(groupdict['month'], calendar.month_abbr)
          if month_num <= 0:
              return None
          try:
              year = int(groupdict['year'])
              day  = int(groupdict['day'])    
          except:
              return None    
          return datetime.datetime(year, month_num, day)
  
      return None         
  
  def parse_webpage(webpage, parser):
      try:
          d = BeautifulSoup(webpage, parser)
          return d
      except:
          return None
  
  def url_to_filename(url, catchpath, catchquery):
      htuple = urllib.parse.urlparse(url)
      path   = htuple[2]
  
      words = []
  
      if catchpath:
          pathwords = path.split('/')
          words.extend(pathwords)
      
      if catchquery:
          qs = htuple[4].split('&')
          qdict = {}
          for q in qs:
              x = q.split('=')
              if len(x) == 2:
                  qdict[x[0]] = x[1]
          for q in catchquery:
              if q in qdict:
                  words.append(qdict[q])
  
      if words:
          wordlist = []
          for word in words:
              word =  word.replace('/', '_')
              word = word.strip()
              wordlist.append(word)
              
          filename = '_'.join(wordlist)
          return filename
      return None
  
  def get_tag_contents(node):
      if type(node) == NavigableString:
          return '%s' % node 
  
      retval = [] 
      for content in node.contents:
          if type(content) == NavigableString:
              retval.append(content)
          elif type(content) == Tag and content.name not in ['style', 'script']:
              if content.name not in ['span']:
                  retval.append(' ')
              retval.append(get_tag_contents(content))
  
      return ''.join(retval) 
  
  def get_date_from_title(title):
      months =  '|'.join(calendar.month_name[1:]) 
      reobj = re.search(r'(?P<day>\d+)\s*(st|nd|rd|th)\s*(?P<month>%s)\s*(?P<year>\d{4})\b' % months, title, re.IGNORECASE)
      if not reobj:
          return None
  
      groupdict = reobj.groupdict()
  
      day    = groupdict['day']
      month  = groupdict['month']
      year   = groupdict['year']
  
      month_num = get_month_num(groupdict['month'], calendar.month_name)
      if month_num <= 0:
          return None
  
      try:
          dateobj = datetime.date(int(year), month_num, int (day))
      except:    
          dateobj = None    
      return dateobj
          
  def tag_contents_without_recurse(tag):
      contents = []
      for content in tag.contents:
          if type(content) == NavigableString:
              contents.append(content)
  
      return contents
   
  def mk_dir(dirname):
      if not os.path.exists(dirname):
          os.mkdir(dirname)
  
  def pad_zero(t):
      if t < 10:
          tstr = '0%d' % t
      else:
          tstr = '%d' % t
  
      return tstr
  
  def get_egz_date(dateobj):
      return '%s-%s-%s' % (pad_zero(dateobj.day), calendar.month_abbr[dateobj.month], dateobj.year)
  
  def dateobj_to_str(dateobj, sep, reverse = False):
      if reverse:
          return '%s%s%s%s%s' % (pad_zero(dateobj.year), sep, \
                  pad_zero(dateobj.month), sep, pad_zero(dateobj.day))
      else:
          return '%s%s%s%s%s' % (pad_zero(dateobj.day), sep, \
                  pad_zero(dateobj.month), sep, pad_zero(dateobj.year))
    
  
  URL        = 'url'
  HREF       = 'href'
  TITLE      = 'title'
  DATE       = 'date'
  MINISTRY   = 'ministry'
  SUBJECT    = 'subject'
  GZTYPE     = 'gztype'
  
  _illegal_xml_chars_RE = re.compile('[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
  
  def replace_xml_illegal_chars(val, replacement=' '):
      """Filter out characters that are illegal in XML."""
  
      return _illegal_xml_chars_RE.sub(replacement, val)
  
  class MetaInfo(dict):
      def __init__(self):
          dict.__init__(self)
  
      def copy(self):
          m = MetaInfo()
          for k, v in self.items():
              m[k] = v
          return m
   
      def set_field(self, field, value):
          if type(value) in (str,):
              value = replace_xml_illegal_chars(value)
          self.__setitem__(field, value)
  
      def get_field(self, field):
          if field in self:
              return self.get(field)
          return None
  
      def set_date(self, value):
          self.set_field(DATE, value)
  
      def set_title(self, value):
          self.set_field(TITLE, value)
  
      def set_url(self, value):
          self.set_field(URL, value)
  
      def set_href(self, value):
          self.set_field(HREF, value)
  
      def set_subject(self, value):
          self.set_field(SUBJECT, value)
  
      def set_ministry(self, value):
          self.set_field(MINISTRY, value)
  
      def set_gztype(self, value):
          self.set_field(GZTYPE, value)
  
      def get_url(self):
          return self.get_field(URL)
  
      def get_href(self):
          return self.get_field(HREF)
  
      def get_title(self):
          return self.get_field(TITLE)
  
      def get_date(self):
          return self.get_field(DATE)
  
      def get_ministry(self):
          return self.get_field(MINISTRY)
  
      def get_subject(self):
          return self.get_field(SUBJECT)
  
      def get_gztype(self, value):
          return self.get_field(GZTYPE)
  
  def stats_to_message(stats):
      rawstats  = stats[0]
      metastats = stats[1]
  
      messagelist = ['Stats on documents']
      messagelist.append('======================')
      courtnames = [x['courtname'] for x in rawstats]
      rawnum     = {x['courtname']: x['num'] for x in rawstats}
      metanum    = {x['courtname']: x['num'] for x in metastats}
  
      for courtname in courtnames:
          if courtname in metanum:
              meta = metanum[courtname]
          else:
              meta = 0
          messagelist.append('%s\t%s\t%s' % (rawnum[courtname], meta, courtname))
   
      return '\n'.join(messagelist)
  
  
  def get_file_type(filepath):
      mtype = magic.from_file(filepath, mime = True)
  
      return mtype
  
  def get_buffer_type(buff):
      mtype = magic.from_buffer(buff, mime=True)
  
      return mtype
  
  
  def get_file_extension(mtype):
      if re.match('text/html', mtype):
          return 'html'
      elif re.match('application/postscript', mtype):
          return 'ps'
      elif re.match('application/pdf', mtype):
          return 'pdf'
      elif re.match('text/plain', mtype):
          return 'txt'
      elif re.match('image/png', mtype):
          return 'png'
      return 'unkwn'
  
  def extract_links_from_pdf(fileobj):
      doc = PdfFileReader(fileobj)
      annots = [page.get('/Annots') for page in doc.pages]
  
      annots = [note.getObject() for note in annots if note is not None]
  
      annots = reduce(lambda x, y: x + y, annots)
  
      links = []
      for note in annots:
          link = note.getObject().get('/A')
          if link:
              launch = link.getObject().get('/F')
              if launch:
                  href = launch.getObject().get('/F')
                  if href:
                      links.append(href)
      return links
  
  def setup_logging(loglevel, logfile):
      leveldict = {'critical': logging.CRITICAL, 'error': logging.ERROR, \
                   'warning': logging.WARNING,   'info': logging.INFO, \
                   'debug': logging.DEBUG}
  
      logfmt  = '%(asctime)s: %(name)s: %(levelname)s %(message)s'
      datefmt = '%Y-%m-%d %H:%M:%S'
      if logfile:
          logging.basicConfig(\
              level   = leveldict[loglevel], \
              format  = logfmt, \
              filename = logfile, \
              datefmt = datefmt \
          )
      else:
          logging.basicConfig(\
              level   = leveldict[loglevel], \
              format  = logfmt, \
              datefmt = datefmt \
          )
  
  
  
  
  if __name__ == '__main__':
      print(extract_links_from_pdf(open(sys.argv[1], 'rb')))
  
  