
    |`,                     T   d Z ddlmZmZmZmZ ddlZddlZddlZddl	Z	ddl
mZ ddlmZ ddlmZ ddlmZ ddlmZ e	j(                  d	k  ZereecZZerdd
lmZ ddlmZ ddlmZ ddlmZ ddl m!Z! ndd
l"mZ ddl#mZ ddl$mZ ddl%m!Z! erddl&m'Z' e'd        Z(nddl&m(Z( ddl)m*Z*  e*jV                  d      Z,ddgZ-d>dZ. G d de      Z/d?dZ0 ed      duZ1e1r@e,je                  d       ddl3m4Z5 ddl6m7Z7 e5jp                  Z8e5jr                  jt                  Z:nddl;m5Z5 ddl<m7Z7  G d d       Z8d! Z:i Z= G d" d#      Z> G d$ d%e>      Z? G d& d'e>      Z@ G d( d)      ZAd* ZBd+ ZCd, ZDd@d-ZE G d. d/      ZFeBeCeDd0ZG eFeG      ZH	  ed       eej                  d1      d2 d3 d4ZJ eFeJ      ZK	 eLeMeNeOej                  ej                  ej                  ej                  ej                  ej                  d5
ZV eFeV      ZW	 d6 ZXdAd7ZYd8 ZZd9 Z[dBd:Z\d; Z]dAd<Z^e_d=k(  r e^        yy)Ca  Piculet is a module for scraping XML and HTML documents using XPath queries.

It consists of this single source file with no dependencies other than
the standard library, which makes it very easy to integrate into applications.
It has been tested with Python 2.7, Python 3.4+, PyPy2 5.7+, and PyPy3 5.7+.

For more information, please refer to the documentation:
https://piculet.readthedocs.io/
    )absolute_importdivisionprint_functionunicode_literalsN)ArgumentParser)deque)partial)
itemgetter)find_loader)   r   )escape)
HTMLParser)StringIO)name2codepoint)urlopen)contextmanagerc              #      K   t         j                  | c}t         _        	 |  |t         _        y# |t         _        w xY ww)z3Context manager for temporarily redirecting stdout.N)sysstdout)
new_stdout
old_stdouts     :/usr/lib/python3/dist-packages/imdb/parser/http/piculet.pyredirect_stdoutr   >   s3      "%Z
CJ	$#CJCJs   A 0 A =A )r   )loggerpiculets<   <meta http-equiv="content-type" content="text/html; charset=s   <meta charset="c                 ^   |t         D ]d  }| j                  |      }|dk\  s|t        |      z   }| j                  d|      }| || j                  d      }t        j                  d|        n t        j                  d|       |}t        j                  d|       | j                  |      S )a  Decode an HTML document according to a character set.

    If no character set is given, this will try to figure it out
    from the corresponding ``meta`` tags.

    :sig: (bytes, Optional[str], Optional[str]) -> str
    :param content: Content of HTML document to decode.
    :param charset: Character set of the page.
    :param fallback_charset: Character set to use if it can't be figured out.
    :return: Decoded content of the document.
    r      "asciizcharset found in "meta": "%s"z'charset not found, using fallback: "%s"zdecoding for charset: "%s")_CHARSET_TAGSfindlendecode_loggerdebug)contentcharsetfallback_charsettagstartcharset_startcharset_ends          r   decode_htmlr,   Z   s       
	'CLL%Ez %C 0%ll4?!-<CCGL=wG
	' MMCEUV&GMM.8>>'""    c                   L     e Zd ZdZh dZ	 d	 fd	Zd Zd Zd Zd Z	d Z
 xZS )
HTMLNormalizerzZHTML cleaner and XHTML convertor.

    DOCTYPE declarations and comments are removed.
    >   brhrimglinkmetainputc                 
   t         rt        j                  |        nt        | 	  d       |t	        |      n	t	               | _        |t	        |      n	t	               | _        t               | _        t               | _	        y)zInitialize this normalizer.

        :sig: (Optional[Iterable[str]], Optional[Iterable[str]]) -> None
        :param omit_tags: Tags to remove, along with all their content.
        :param omit_attrs: Attributes to remove.
        T)convert_charrefsN)
PY2r   __init__superset	omit_tags
omit_attrsr   
_open_tags_open_omitted_tags)selfr<   r=   	__class__s      r   r9   zHTMLNormalizer.__init__   sc     %Gd3+4+@Yce-7-C#j/  '"''r-   c                    || j                   v r1t        j                  d|       | j                  j	                  |       | j                  s6d|v rt        d|z  d       y|dk(  r8| j                  d   dk(  r&t        j                  d	       | j                  d       g }|D ]j  \  }}|| j                  v rt        j                  d
||       ,|t        j                  d||       d}d|t        |d      dz  }|j	                  |       l d|t        |      dkD  rddj                  |      z   nd|| j                  v rdnddz  }t        |d       || j                  vr| j                  j	                  |       yyy)z&Process the starting of a new element.zomitting: "%s"@z
&lt;%s&gt; endNliz=opened "li" without closing previous "li", adding closing tagzomitting "%s" attribute of "%s"z7no value for "%s" attribute of "%s", adding empty valuez%(name)s="%(value)s"T)quotenamevaluez<%(tag)s%(attrs)s%(slash)s>r    z /)r(   attrsslash)r<   r#   r$   r?   appendprintr>   handle_endtagr=   html_escaper!   joinSELF_CLOSING_TAGS)r@   r(   rN   
attributes	attr_name
attr_valuemarkuplines           r   handle_starttagzHTMLNormalizer.handle_starttag   s   $.. MM*C0##**3/&&czlS(b1t$//""5"=]^""4(J). *%	:/MM"CYPST%MM"["+S2!#J/%(4@3  !!&)* 19<Z19L# 44RT!$(>(>!>B4 D
 $B$000&&s+ 1; 'r-   c                    | j                   s)|| j                  vr| j                  d   }|dk(  r+|dk(  r&t        j	                  d       | j                  d       ||k(  r-t        dd|iz  d       | j                  j                          y|| j                  vrt        j	                  d	|       y|| j                  d
   k(  rpt        j	                  d||       t        dd|iz  d       t        dd|iz  d       | j                  j                          | j                  j                          yyy|| j                  v r.|| j                   d   k(  r| j                   j                          yyy)z!Process the ending of an element.rH   ulrG   z:closing "ul" without closing last "li", adding closing tagz
</%(tag)s>r(   rD   rE   z$closing tag "%s" without opening tagz9unexpected closing tag "%s" instead of "%s", closing bothN)	r?   rU   r>   r#   r$   rR   rQ   popr<   )r@   r(   lasts      r   rR   zHTMLNormalizer.handle_endtag   sD   &&$000r*4KddlMM"^_&&t,$;,%52>OO'')/MM"H#NDOOB//MM"]"%t-,%6B?,%52>OO'')OO'') 0 1& T^^##1H1H1L*L##'') +M#r-   c                     | j                   s@t        |      }t        t        r!t	        |t
              r|j                  d      n|d       yy)z!Process collected character data.utf-8rD   rE   N)r?   rS   rQ   r8   
isinstancebytesr"   )r@   datarZ   s      r   handle_datazHTMLNormalizer.handle_data   s;    &&t$D#*T52I$++g&tY[\ 'r-   c                 X    t        j                  |      }|t        dd|iz  d       yy)zProcess an entity reference.Nz
&#%(ref)d;refrD   rE   )r   getrQ   )r@   rK   nums      r   handle_entityrefzHTMLNormalizer.handle_entityref   s1       &?,%-26 r-   c                 (    t        dd|iz  d       y)zProcess a character reference.z
&#%(ref)s;rh   rD   rE   N)rQ   )r@   rK   s     r   handle_charrefzHTMLNormalizer.handle_charref   s     	leT]*3r-   NN)__name__
__module____qualname____doc__rU   r9   r[   rR   rf   rk   rm   __classcell__rA   s   @r   r/   r/   v   s4    
 E)*&#,J*6]74r-   r/   c                     t               }t        ||      }t        |      5  |j                  |        ddd       |j	                         S # 1 sw Y   |j	                         S xY w)aD  Clean HTML and convert to XHTML.

    :sig: (str, Optional[Iterable[str]], Optional[Iterable[str]]) -> str
    :param document: HTML document to clean and convert.
    :param omit_tags: Tags to exclude from the output.
    :param omit_attrs: Attributes to exclude from the output.
    :return: Normalized XHTML content.
    )r<   r=   N)r   r/   r   feedgetvalue)documentr<   r=   out
normalizers        r   html_to_xhtmlr{      sS     *C)
KJ		 "!"<<>"<<>s   AA%lxmlz
using lxml)etree)Element)ElementTreec                       e Zd ZdZd Zd Zy)XPathzAn XPath expression evaluator.

        This class is mainly needed to compensate for the lack of ``text()``
        and ``@attr`` axis queries in ElementTree XPath support.
        c                    fd}fd}d }d   dk(  rdz   j                  d      r
|}|| _        y	j                  d      r
|}|| _        y	j                  d      }|d	d
 |d
   }}|j                  d      r(t        |dj	                  |      |dd	       }|| _        y	t        t
        j                        }|| _        y	)zInitialize this evaluator.

            :sig: (str) -> None
            :param path: XPath expression to evaluate.
            c                     | j                  d d       D cg c]  }|j                         D ]  }|s|	  c}}S c c}}w )Ni)findallitertext)elementetpaths      r   
descendantz"XPath.__init__.<locals>.descendant  s;    #*??49#=Yaqzz|Y!WXYYYYs   >>c           
          | j                  d d       D cg c]A  }|j                  g|D cg c]  }|j                  r|j                  nd c}z   D ]  }|r| C c}}}S c c}w c c}}}w )NirD   )r   texttail)r   r   r   cr   s       r   childzXPath.__init__.<locals>.child!  s{    #*??49#= Z Za#$66(PQ-R1affB.F-R"RZWX  Z Z Z-RZs   A*!A%A*%A*c                     | j                  |      D cg c]  }|j                  j                  |       }}|D cg c]  }||	 c}S c c}w c c}w N)r   attribri   )r   subpathattrr   resultrs         r   	attributez!XPath.__init__.<locals>.attribute&  sI    6=oog6NO!((,,t,OO#);aQ];; P;s   "AAAr   /.z//text()z/text()NrH   rC      )r   r   )r   )endswithsplit
startswithr	   rT   r~   r   _apply)	r@   r   r   r   r   r   stepsfrontr`   s	    `       r   r9   zXPath.__init__  s    ZZ
< Aw#~ Tz}}Z(# !DK y) !DK 

3#CRj%)t??3'$YdSTSUhWF !DK %W__4@F DKr-   c                 $    | j                  |      S )zApply this evaluator to an element.

            :sig: (Element) -> XPathResult
            :param element: Element to apply this expression to.
            :return: Elements or strings resulting from the query.
            )r   r@   r   s     r   __call__zXPath.__call__>  s     ;;w''r-   N)ro   rp   rq   rr   r9   r    r-   r   r   r     s    	%	!N	(r-   r   c                 $     t        |      |       S r   )r   )r   ps     r   <lambda>r   G  s    q! r-   c                   6    e Zd ZdZddZd ZddZed        Zy)		Extractorz?Abstract base extractor for getting data out of an XML element.Nc                 H    || _         	 |t        |      | _        yd| _        y)zInitialize this extractor.

        :sig: (Optional[Transformer], Optional[str]) -> None
        :param transform: Function to transform the extracted value.
        :param foreach: Path to apply for generating a collection of values.
        N)	transformr   foreach)r@   r   r   s      r   r9   zExtractor.__init__W  s/     #8)0)<uW~B CGBr-   c                     t        d      )zGet the raw data from an element using this extractor.

        :sig: (Element) -> ExtractedItem
        :param element: Element to apply this extractor to.
        :return: Extracted raw data.
        z.Concrete extractors must implement this method)NotImplementedErrorr   s     r   applyzExtractor.applyd  s     ""RSSr-   c                 ~    | j                  |      }|
|t        u s|s|S | j                  |S | j                  |      S )a8  Get the processed data from an element using this extractor.

        :sig: (Element, Optional[bool]) -> Any
        :param element: Element to extract the data from.
        :param transform: Whether the transformation will be applied or not.
        :return: Extracted and optionally transformed data.
        )r   _EMPTYr   )r@   r   r   rL   s       r   extractzExtractor.extractm  sA     

7#Mu	L.uIDNN54IIr-   c                    | j                  d      }|d}n"t        j                  |      }|t        d      | j                  d      }| j                  d      }|I| j                  d      }|d}n"t        j                  |      }|t        d      t	        ||||      }|S | j                  d	      }|D 	cg c]  }	t
        j                  |	       }
}	t        |
| j                  d
      ||      }|S c c}	w )zGenerate an extractor from a description map.

        :sig: (Mapping[str, Any]) -> Extractor
        :param item: Extractor description.
        :return: Extractor object.
        :raise ValueError: When reducer or transformer names are unknown.
        r   NzUnknown transformerr   r   reducezUnknown reducerr   r   itemssection)r   r   r   )ri   transformers
ValueErrorreducersPathRulefrom_mapRules)itemtransformerr   r   r   reducerr   	extractorr   iruless              r   r   zExtractor.from_mapz  s    hh{+I$((5I  !677((9%xxhhx(G!g.>$%677T6YPI  HHW%E/45!T]]1%5E5eTXXi-@(17DI 	 6s   ;C9rn   )T)	ro   rp   rq   rr   r9   r   r   staticmethodr   r   r-   r   r   r   T  s+    ICTJ # #r-   r   c                   *     e Zd ZdZd fd	Zd Z xZS )r   z4An extractor for getting text out of an XML element.c                     t         rt        j                  | ||       nt        | 	  ||       t	        |      | _        	 |t        j                  }|| _        y)a  Initialize this extractor.

        :sig: (
                str,
                Optional[Reducer],
                Optional[PathTransformer],
                Optional[str]
            ) -> None
        :param path: Path to apply to get the data.
        :param reduce: Function to reduce selected texts into a single string.
        :param transform: Function to transform extracted value.
        :param foreach: Path to apply for generating a collection of data.
        r   N)	r8   r   r9   r:   r   r   r   concatr   )r@   r   r   r   r   rA   s        r   r9   zPath.__init__  sU     ty'JGy'B$K	7>__FEr-   c                 n    | j                  |      }t        |      dk(  rd}|S | j                  |      }|S )zApply this extractor to an element.

        :sig: (Element) -> str
        :param element: Element to apply this extractor to.
        :return: Extracted text.
        r   N)r   r!   r   )r@   r   selectedrL   s       r   r   z
Path.apply  s?     99W%x=AE
  KK)Er-   NNNro   rp   rq   rr   r9   r   rs   rt   s   @r   r   r     s    >F8r-   r   c                   *     e Zd ZdZd fd	Zd Z xZS )r   z:An extractor for getting data items out of an XML element.c                     t         rt        j                  | ||       nt        | 	  ||       || _        	 |t        |      | _        yd| _        y)a  Initialize this extractor.

        :sig:
            (
                Sequence[Rule],
                str,
                Optional[MapTransformer],
                Optional[str]
            ) -> None
        :param rules: Rules for generating the data items.
        :param section: Path for setting the root of this section.
        :param transform: Function to transform extracted value.
        :param foreach: Path for generating multiple items.
        r   N)r8   r   r9   r:   r   r   r   )r@   r   r   r   r   rA   s        r   r9   zRules.__init__  sZ     ty'JGy'B
2)0)<uW~H CGHr-   c                    | j                   |}nx| j                  |      }t        |      dk(  rt        j                  d       t        S t        |      dkD  rt        d      |d   }t        j                  d|j                         i }| j                  D ]$  }|j                  |      }|j                  |       & t        |      dkD  r|S t        S )zApply this extractor to an element.

        :sig: (Element) -> Mapping[str, Any]
        :param element: Element to apply the extractor to.
        :return: Extracted mapping.
        r   zNo section root foundr   z.Section path should select exactly one elementzMoving root to %s element)
r   r!   r#   r$   r   r   r(   r   r   update)r@   r   subrootsubrootsre   rule	extracteds          r   r   zRules.apply  s     <<G||G,H8}!568}q  !QRRqkGMM5w{{CJJ 	#DW-IKK	"	# 4y1}t0&0r-   r   r   rt   s   @r   r   r     s    DI41r-   r   c                   .    e Zd ZdZddZed        Zd Zy)r   z?A rule describing how to get a data item out of an XML element.Nc                 X    || _         	 || _        	 |t        |      | _        yd| _        y)a"  Initialize this rule.

        :sig: (Union[str, Extractor], Extractor, Optional[str]) -> None
        :param key: Name to distinguish this data item.
        :param extractor: Extractor that will generate this data item.
        :param foreach: Path for generating multiple items.
        N)keyr   r   r   )r@   r   r   r   s       r   r9   zRule.__init__  s9     1":)0)<uW~< CG<r-   c                     | d   }t        |t              r|nt        j                  |      }t        j                  | d         }t	        ||| j                  d            S )zGenerate a rule from a description map.

        :sig: (Mapping[str, Any]) -> Rule
        :param item: Item description.
        :return: Rule object.
        r   rL   r   )r   r   r   )rc   strr   r   r   ri   )r   item_keyr   rL   s       r   r   zRule.from_map  sT     ;$Xs3h9K9KH9U""4=1udhhy6IJJr-   c                    i }| j                   |gn| j                  |      }|D ]:  }t        | j                  t              r| j                  n| j                  j	                  |      }|H| j
                  j                   ,| j
                  j	                  |      }||t        u r|||<   | j
                  j                  |      D cg c]  }| j
                  j	                  |d      ! }}|D 	cg c]  }	|	|	t        us|	 }
}	t        |
      dk(  r| j
                  j                  |
n(t        t        | j
                  j                  |
            ||<   = |S c c}w c c}	w )zExtract data out of an element using this rule.

        :sig: (Element) -> Mapping[str, Any]
        :param element: Element to extract the data from.
        :return: Extracted data.
        F)r   r   )r   rc   r   r   r   r   r   r!   r   listmap)r@   r   re   r   r   r   rL   r   
raw_valuesvvaluess              r   r   zRule.extract+  sY     $ 4G9$,,w:O 	@G )37$((TXX=M=Mg=VC{ ~~%%-..w7Mu!S	
 (,~~'='=g'FH"# #nn44Q%4H H
 H%/YAMQW!YYv;!#&*nn&>&>&FFT^^55v>? S	1	@6 HYs   $E%6E*>E*E*r   )ro   rp   rq   rr   r9   r   r   r   r   r-   r   r   r   
  s%    I=" 
K 
K$r-   r   c                 
   t         rt        j                  j                  }n^| j                  j                  d      }|A| j                         D ci c]  }|D ]  }||  c}}j
                  }|| j                  d<    t        |      |       }t        j                  dt        |      |       t        |      dkD  r?|D ]9  }t        j                  d|j                          ||      j                  |       ; yyc c}}w )zRemove selected elements from the tree.

    :sig: (Element, str) -> None
    :param root: Root element of the tree.
    :param path: XPath to select the elements to remove.
    _get_parentNz%removing %s elements using path: "%s"r   zremoving element: "%s")	_USE_LXMLr   _Element	getparentr   ri   iterr   r#   r$   r!   r(   remove)rootr   
get_parentr   r   elementsr   s          r   remove_elementsr   R  s      ))33
 [[__]3
(,		?1Q?!Q$?!?CCJ)3DKK&uT{4 HMM93x=$O
8}q 	0GMM2GKK@w&&w/	0 	 @s   C?c                 :    t        |      |       }t        j                  dt        |      |       |D ]  }t	        |t
              r|n#t        j                  |      j                  |      }|!t        j                  d|j                         \t	        |t
              r|n#t        j                  |      j                  |      }|!t        j                  d|j                         t        j                  d|||j                         ||j                  |<    y)a  Set an attribute for selected elements.

    :sig:
        (
            Element,
            str,
            Union[str, Mapping[str, Any]],
            Union[str, Mapping[str, Any]]
        ) -> None
    :param root: Root element of the tree.
    :param path: XPath to select the elements to set attributes for.
    :param name: Description for name generation.
    :param value: Description for value generation.
    %updating %s elements using path: "%s"Nz,no attribute name generated for "%s" elementz-no attribute value generated for "%s" elementz.setting "%s" attribute to "%s" on "%s" element)r   r#   r$   r!   rc   r   r   r   r   r(   r   )r   r   rK   rL   r   r   rW   rX   s           r   set_element_attrr   j  s     uT{4 HMM93x=$O /&tS1Dt$,,W5 	MMH'++V(4Uu%--g6 	MMI7;;WFW[[	:$.y!/r-   c                 0    t        |      |       }t        j                  dt        |      |       |D ]`  }t	        |t
              r|n#t        j                  |      j                  |      }t        j                  d||j                         ||_
        b y)a  Set the text for selected elements.

    :sig: (Element, str, Union[str, Mapping[str, Any]]) -> None
    :param root: Root element of the tree.
    :param path: XPath to select the elements to set attributes for.
    :param text: Description for text generation.
    r   z$setting text to "%s" on "%s" elementN)r   r#   r$   r!   rc   r   r   r   r   r(   r   )r   r   r   r   r   element_texts         r   set_element_textr     s     uT{4 HMM93x=$O $)$4tt$,,W5 	 	<lGKKX#$r-   c                     t         r| j                  d      n| }t        r6|r4t        j	                  d       ddl}|j                  j                  |      S t        j                  |      S )zBuild a tree from an XML document.

    :sig: (str, Optional[bool]) -> Element
    :param document: XML document to build the tree from.
    :param force_html: Force to parse from HTML without converting.
    :return: Root element of the XML tree.
    rb   zusing lxml html builderr   N)	r8   encoder   r#   info	lxml.htmlhtml
fromstringr   )rx   
force_htmlr%   r|   s       r   
build_treer     sQ     +.hoog&8GZ./yy##G,,!!'**r-   c                   "    e Zd ZdZd Zd Zd Zy)Registryz$A simple, attribute-based namespace.c                 :    | j                   j                  |       y)zInitialize this registry.

        :sig: (Mapping[str, Any]) -> None
        :param entries: Entries to add to this registry.
        N)__dict__r   )r@   entriess     r   r9   zRegistry.__init__  s     	W%r-   c                 8    | j                   j                  |      S )zGet the value of an entry from this registry.

        :sig: (str) -> Any
        :param item: Entry to get the value for.
        :return: Value of entry.
        )r   ri   )r@   r   s     r   ri   zRegistry.get  s     }}  &&r-   c                 "    || j                   |<   y)zRegister a new entry in this registry.

        :sig: (str, Any) -> None
        :param key: Key to search the entry in this registry.
        :param value: Value to store for the entry.
        N)r   )r@   r   rL   s      r   registerzRegistry.register  s     #cr-   N)ro   rp   rq   rr   r9   ri   r  r   r-   r   r   r     s    .&'#r-   r   )r   set_attrset_textrD   c                     t        j                  dddj                  |       j                  dd            j	                         S )Nz\s+rM   rD       )resubrT   replacestripxss    r   r   r     s1    vsBGGBK,?,?,LMSSU r-   c                     t        j                  dddj                  |       j                         j	                  dd            S )Nz
[^a-z0-9_]rD   rM   _)r  r  rT   lowerr  r
  s    r   r   r     s3    BFF<RWWR[5F5F5H5P5PQTVY5Z[ r-   )firstr   clean	normalize)
intfloatboolr!   r  upper
capitalizelstriprstripr	  c                     |D ]^  }|d   }|dk(  rt        | |d          |dk(  rt        | |d   |d   |d          ;|dk(  rt        | |d   |d	   
       Ut        d       y)zProcess a tree before starting extraction.

    :sig: (Element, Sequence[Mapping[str, Any]]) -> None
    :param root: Root of tree to process.
    :param pre: Descriptions for processing operations.
    opr   r   r  rK   rL   rJ   r  r   )r   zUnknown preprocessing operationN)r   r   r   r   )r   prestepr  s       r   
preprocessr    s}      	@$Z>D$v,/:T4<d6l$w-X:T4<d6lC>??	@r-   c                     t        |D cg c]  }t        j                  |       c}|      }|j                  |       S c c}w )a  Extract data from an XML element.

    :sig:
        (
            Element,
            Sequence[Mapping[str, Any]],
            Optional[str]
        ) -> Mapping[str, Any]
    :param element: Element to extract the data from.
    :param items: Descriptions for extracting items.
    :param section: Path to select the root element for these items.
    :return: Extracted data.
    r   )r   r   r   r   )r   r   r   r   r   s        r   r   r     s8     5944==&97KE==!! :s   A c                     t        |       }|j                  d      }|t        ||       t        ||j                  d      |j                  d            }|S )zExtract data from a document after optionally preprocessing it.

    :sig: (str, Mapping[str, Any]) -> Mapping[str, Any]
    :param document: Document to scrape.
    :param spec: Extraction specification.
    :return: Extracted data.
    r  r   r   r  )r   ri   r  r   )rx   specr   r  re   s        r   scraper"    sO     hD
((5/C
44'*DHHY4GHDKr-   c                 |   | dk(  r4t         j                  d       t        j                  j	                         }nat         j                  dt
        j                  j                  |              t        | d      5 }t        |j	                               }ddd       t        t              d       y# 1 sw Y    xY w)zyConvert an HTML file into XHTML and print.

    :sig: (str) -> None
    :param source: Path of HTML file to convert.
    -zreading from stdinzreading from file: "%s"rbNrD   rE   )r#   r$   r   stdinreadosr   abspathopenr,   rQ   r{   )sourcer%   fs      r   h2xr-  -  s     }*+)).."/1HI&$ 	,1!!&&(+G	,	-
 b)	, 	,s   9B22B;c                    t         j                  dt        j                  j	                  |             t        j                  j                  |      d   dk(  r't        d      t        d      ddl}|j                  }nt        j                  }t        |      5 } ||j                               }ddd       | j                  d      r;t         j                  d	|        t        |       5 }|j                         }ddd       nXt         j                  d
t        j                  j	                  |              t        | d      5 }|j                         }ddd       t!              }|dk(  r t         j                  d       t#        |      }t%        |      }	t'        t        j(                  |	dd             y# 1 sw Y   xY w# 1 sw Y   txY w# 1 sw Y   xY w)a  Scrape data from a file path or a URL and print.

    :sig: (str, str, Optional[str]) -> None
    :param address: File path or URL of document to scrape.
    :param spec: Path of spec file.
    :param content_format: Whether the content is XML or HTML.
    zloading spec from file: "%s"rH   z.yamlyamlNzYAML support not availabler   )zhttp://zhttps://zloading url: "%s"zloading file: "%s"r%  r   z!converting html document to xhtml   T)indent	sort_keys)r#   r$   r(  r   r)  splitextr   RuntimeErrorr/  loadjsonloadsr*  r'  r   r   r,   r{   r"  rQ   dumps)
addressr!  content_formatr/  spec_loaderr,  spec_mapr%   rx   re   s
             r   scrape_documentr=  =  s{    MM0"''//$2GH	wwb!W,v&;<<iijj	d )qqvvx() 12)73W 	ffhG	 	 	*BGGOOG,DE'4  	AffhG	7#H9: * (H%D	$**T!t
45') )
	 		 	s$   F<,G	G<G	GGc                    t        |       }|j                  ddd       |j                  ddd	       |j                  d
d
      }d|_        |j	                  dd      }|j                  dd       |j                  d        |j	                  dd      }|j                  dd       |j                  dddd       |j                  ddd	       |j                  d        |S )zBuild a parser for command line arguments.

    :sig: (str) -> ArgumentParser
    :param prog: Name of program.
    :return: Parser for arguments.
    progz	--versionversionz%(prog)s 1.0b7)actionrA  z--debug
store_truezenable debug messages)rB  helpcommand)metavardestTr-  zconvert HTML to XHTML)rD  filezfile to convertc                 ,    t        | j                        S r   )r-  rH  as    r   r   zmake_parser.<locals>.<lambda>t  s    3qvv; r-   )funcr"  zscrape a documentrx   z&file path or URL of document to scrapez-sz--specz	spec file)requiredrD  z--htmlzdocument is in HTML formatc                 l    t        | j                  | j                  | j                  rd      S d      S )Nr   xml)r:  )r=  rx   r!  r   rJ  s    r   r   zmake_parser.<locals>.<lambda>z  s*    o	

AFFQVV6/ AF/ r-   )r   add_argumentadd_subparsersrM  
add_parserset_defaults)r@  parsercommands
h2x_parserscrape_parsers        r   make_parserrX  d  s    &F
I?OP
	,=TU$$YY$GHH$$U1H$IJF):;!67''7J'KMz0XYtX;OxC_` %  Mr-   c                    | | nt         j                  } t        d      }|j                  | dd       }|j                  r9t
        j                  t
        j                         t        j	                  d       	 |j                  |       y# t        $ r:}t        |t         j                         t        j                  d       Y d}~yd}~ww xY w)zEntry point of the command line utility.

    :sig: (Optional[List[str]]) -> None
    :param argv: Command line arguments.
    Nr   r?  r   )levelzrunning in debug mode)rH  )r   argvrX  
parse_argsr$   loggingbasicConfigDEBUGr#   rL  	ExceptionrQ   stderrexit)r[  rT  	argumentsr   s       r   mainrd    s     #4Di(F!!$qr(+I '--0-.y! acjj!s   ;B 	C0CC__main__)Nrb   rn   )Fr   )rO  )`rr   
__future__r   r   r   r   r6  r(  r  r   argparser   collectionsr   	functoolsr	   operatorr
   pkgutilr   version_infor8   unicoder   rd   cgir   rS   r   r   htmlentitydefsr   urllib2r   r   html.parseriourllib.request
contextlibr   r   imdb.parser.http.loggingr   getChildr#   r   r,   r/   r{   r   r   r|   r}   r   
lxml.etreer~   r   r   xpath	xml.etreexml.etree.ElementTreer   r   r   r   r   r   r   r   r   r   _PREPROCESSORSpreprocessorsrT   	_REDUCERSr   r  r  r  r!   r  r  r  r  r  r	  _TRANSFORMERSr   r  r   r"  r-  r=  rX  rd  ro   r   r-   r   <module>r     sZ    S R  	 	 
 #     
 #JC )%!-*&& )$ $ + +
&//)
$ D#8m4Z m4l0 t+	LL)"E  &&E%-5( 5(n %E 
J JZ/9 /d41I 41nE EP00 /F$$+ # #>    (  ]chh#U[		 I  YYYY..jjjjYY & @&"$** $6N:. zF r-   