
ƁKc           @   s  d  Z  d Z d i   d i d d  Z d Z d d k l Z l Z d d	 k	 l
 Z
 d d
 k Z d d
 k Z d   Z d   Z d e f d     YZ d d d  Z d   Z e e e e d d  Z d   Z d   Z e   Z d e e e d h  d  Z d f  d     YZ d Z d   Z e d  Z e i e  Z e i d  Z  d   Z! d   Z" e# d   e$ d   D  Z% e% i& e# d!   d" d# d$ D   d%   Z' d&   Z( d'   Z) e i e) e   Z* e i e) e d(   e i+  Z, e i e) e d)   e i+  Z- e i d* e i+  Z. h  e i d+  d, <e i d- e i+  d. <e i d/ e i+  d0 <Z/ d1   Z0 d2 Z1 e i e1  Z2 d3   Z3 e   Z4 d4   Z5 d5   Z6 d6   Z7 d7   Z8 d8   Z9 d9 f  d:     YZ: d;   Z; d<   Z< d=   Z= d>   Z> d?   Z? e   Z@ d
 S(@   s  Python module for web browsing and scraping.

Done:
  - navigate to absolute and relative URLs
  - follow links in page or region
  - find strings or regular expressions: first, all, split
  - find tags: first, last, next, previous, all, splittag
  - find elements: first, last, next, previous, enclosing, all
  - set form fields
  - submit forms
  - strip tags from arbitrary strings of HTML
  - support HTTPS
  - handle entities > 255 and Unicode documents
  - accept and store cookies during redirection
  - store and send cookies according to domain and path

To do:
  - split by element
  - detect ends of elements in most cases even if matching end tags are missing
  - make the line breaks in striptags correctly reflect whitespace significance
  - handle <![CDATA[ marked sections ]]>
  - submit forms with file upload
  - use Regions in striptags instead of duplicating work?
  - remove dependency on urllib.urlencode
s   Ka-Ping Yee <ping@zesty.ca>s   $Date: 2010-02-21 23:49:22 $i   t   /t   -s   $Revision: 1.48 $i(   t   urlsplitt   urljoin(   t   name2codepointNc         O   sX   | i  d t i  } x0 t |  D]" \ } } |  i d | |  }  q" Wt i |  |  S(   s'  Compile a regular expression, substituting in any passed parameters
    for placeholders of the form __0__, __1__, __2__, etc. in the template.
    Specify the named argument 'flags' to set regular expression compilation
    flags; by default, DOTALL is set ('.' matches anything including '
').t   flagss   __%d__(   t   gett   ret   DOTALLt	   enumeratet   replacet   compile(   t   templatet   paramst   kwargsR   t   it   param(    (    s   ./scrape.pyt   regex1   s
     c         O   s-   | i  d d  t i B| d <t |  | |  S(   s  Compile a regular expression, substituting in any passed parameters
    for placeholders of the form __0__, __1__, __2__, etc. in the template.
    Specify the named argument 'flags' to set regular expression compilation
    flags; by default, DOTALL and IGNORECASE are set.R   i    (   R   R   t
   IGNORECASER   (   R   R   R   (    (    s   ./scrape.pyt   iregex;   s    t   ScrapeErrorc           B   s   e  Z RS(    (   t   __name__t
   __module__(    (    (    s   ./scrape.pyR   C   s   t    i    c      	   C   sC  | d | d } xo | i    D]a \ } }	 d i g  }
 | i d  D] } |
 | i   qE ~
  } | | d t |	  d 7} q W| d | 7} | i d  d d d	 g |  d
 j } } d | j o | i d d  \ } } n d d k } | i | i | i  } | d j o t i	 d I| I| IJn | i
 | t |  f  |  d
 j o | i |  p
 | i   } | d j o- t i	 d | i   i d d  i   IJn | i |  t | d  o | i   n g  } y= x6 | o t | d  d j p | i | i    qWWn | i j
 o n Xd i |  S(   sC   Make an HTTP or HTTPS request; return the entire reply as a string.t    s    HTTP/1.0
R   s   : s   
t   @iiP   i  t   httpst   :i   Ni   s   connect:s
   
request: t   flushi    R   (   t   itemst   joint   splitt
   capitalizet   strt   sockett   AF_INETt   SOCK_STREAMt   syst   stderrt   connectt   intt   sslt   makefilet   rstripR
   t   lstript   writet   hasattrR   t   lent   appendt   readt   error(   t   schemet   methodt   hostt   patht   headerst   datat   verboset   requestt   namet   valuet   _[1]t   partt   capnamet   portR"   t   sockt   filet   chunks(    (    s   ./scrape.pyR:   F   s:     9 *) c         C   s   d |  i  d d  d S(   s#   Quote a string literal for /bin/sh.t   's   '\''(   R
   (   t   text(    (    s   ./scrape.pyt
   shellquotee   s    c         C   sB  d d k  } d d k } | i d d  \ } }	 d }
 | o8 t | t  p t |  } n |
 d t |  7}
 n | o |
 d t |  7}
 n | o |
 d t |  7}
 n | o |
 d	 t |  7}
 n |
 d
 t |   7}
 | d j o t i d I|
 IJn | i	 |
 d |	  t
 |	  i   } | i |	  | S(   s@   Use curl to make a request; return the entire reply as a string.iNt   prefixt   scrapes1   curl --include --insecure --silent --max-redirs 0s    --data s    --user-agent s    --referer s
    --cookie R   i   s   execute:s    > (   t   ost   tempfilet   mkstempt
   isinstanceR!   t	   urlencodeRF   R%   R&   t   systemt   openR1   t   remove(   t   urlR8   t   agentt   referrert   cookiesR9   RI   RJ   t   fdt   tempnamet   commandt   reply(    (    s   ./scrape.pyt   curli   s(    c         C   s   h  } x~ |  D]v } d | i  |  o\ xY |  | D]I } | i |  o3 x0 |  | | i   D] \ } } | | | <q] Wq2 q2 Wq q W| S(   sk   Get a dictionary of the cookies from 'cookiejar' that apply to the
    given request host and request path.t   .(   t   endswitht
   startswithR   (   t	   cookiejarR5   R6   RT   t   cdomaint   cpatht   keyR<   (    (    s   ./scrape.pyt
   getcookies   s       c   
   	   C   s   x | D] } g  } | i  d  D]* } | | i   i  d d  d g d  q! ~ } | d t | d  \ } } }	 | |  i |	 i d |  h   i |	 i d d	  h   | <q Wd
 S(   sP   Store cookies in 'cookiejar' according to the given Set-Cookie
    header lines.t   ;t   =i   R   i   i    t   domainR6   R    N(   R   t   stript   dictt
   setdefaultR   (
   R]   R5   t   linest   lineR=   R>   t   pairsR;   R<   t   attrs(    (    s   ./scrape.pyt
   setcookies   s     @!c         C   s  t  |   \ } } }	 }
 } | i d  d } |	 p d }	 | o d p d } | o! t | t  o t |  } n d i g  } t | | |	  i   D] } | d | q ~  } | o t i	 d I|  IJn d d	 k
 } | d
 j p | d j o t | d  o |
 o |	 d |
 7}	 n h  | d <d d <} | o d | d <t |  | d <n | o | | d <n | o | | d <n | o | | d <n t | | | |	 | | |  } n: | d j o t |  | | | | |  } n t | d  h  | d } } } d | j o' | i d d  d g d  \ } } n? t i d |  } | o% | | i    | | i   } } n | i d d  i d d  } | i d d  \ } } t | i   d  } d  i | i   d  } x | i d  D] } | d! j o t i	 d" I| i   IJn | i d# d  \ } } | i   } | | j o | | c d | 7<q| | | <qW| d j o5 t i	 d$ t |  | d j o d% p d f IJn d& | j o! t | | | d& i d   n d | j oY | oQ xN | d i d'  d D]1 } | i   i d(  o | i   d) } PqqWn | o# | t j	 o | i | d*  } n |  | | | | f S(+   sY  Make an HTTP or HTTPS request.  If 'data' is given, do a POST;
    otherwise do a GET.  If 'agent' and/or 'referrer' are given, include
    them as User-Agent and Referer headers in the request, respectively.
    'cookiejar' should have the form {domain: {path: {name: value, ...}}};
    cookies will be sent from it and received cookies will be stored in it.
    Return the 5-element tuple (url, status, message, headers, content)
    where 'url' is the final URL retrieved, 'status' is the integer status
    code, 'message' is the reply status message, 'headers' is a dictionary of
    HTTP headers, and 'content' is a string containing the received content.
    For multiple occurrences of the same header, 'headers' will contain a
    single key-value pair where the values are joined together with newlines.
    If the Content-Type header specifies a 'charset' parameter, 'content'
    will be a Unicode string, decoded using the given charset.  Giving the
    'charset' argument overrides any received 'charset' parameter; a charset
    of RAW ensures that the content is left undecoded in an 8-bit string.R   iR    t   POSTt   GETs   ; s   %s=%ss   fetch:Nt   httpR   R)   t   ?R5   s   */*t   accepts!   application/x-www-form-urlencodeds   content-types   content-lengths
   user-agentt   referert   cookies    not supportedR   s   

i   i   s   ?
[ 	]*?
s   
s   
s   R   i   s   reply:s   : s   content: %d byte%s
t   ss
   set-cookieRb   s   charset=i   t   ignore(   R   R   RL   R!   RM   R   Ra   R   R%   R&   R"   R.   R/   R:   RY   t
   ValueErrorR   t   searcht   startt   endR
   R(   R+   t   lowerRl   Re   R\   t   RAWt   decode(   RQ   R8   RR   RS   t   charsetR9   R]   R3   R5   R6   t   queryt   fragmentR4   R=   t   pairt   cookieheaderR"   R7   RX   t   headt   contentt   matcht   responset   statust   messageRi   R;   R<   R   (    (    s   ./scrape.pyt   fetch   sz    :*
"'% 
+! t   Sessionc           B   sk   e  Z d  Z d d d  Z d d e d d  Z d   Z d d  Z d d d d  Z	 d	   Z
 d
   Z RS(   s  A Web-browsing session.  Exposed attributes:
    
        agent   - the User-Agent string (clients can set this attribute)
        url     - the last successfully fetched URL
        status  - the status code of the last request
        message - the status message of the last request
        headers - the headers of the last request as a dictionary
        content - the content of the last fetched document
        doc     - the Region spanning the last fetched document
    i    c         C   sV   | |  _  d |  _ |  _ |  _ |  _ |  _ d |  _ h  |  _ h  |  _	 g  |  _
 d S(   s   Specify 'agent' to set the User-Agent.  Set 'verbose' to 1, 2, or
        3 to display status messages on stderr during document retrieval.i    N(   RR   t   NoneRQ   R   R   R   t   docR9   R7   R]   t   history(   t   selfRR   R9   (    (    s   ./scrape.pyt   __init__  s    	%			R   i
   c         C   s!  |  i  |  i |  i |  i |  i |  i f } |  i |  } | t j o |  i  } n x t | | |  i	 | | |  i
 |  i  \ |  _  |  _ |  _ |  _ |  _ | oR |  i d j o> d |  i j o. t | |  i d  d } } | d 8} qV q n PqV |  i i |  t |  i  |  _ |  i S(   s)  Navigate to a given URL.  If the URL is relative, it is resolved
        with respect to the current URL.  If 'data' is provided, do a POST;
        otherwise do a GET.  Follow redirections up to 'redirects' times.
        If 'referrer' is given, send it as the referrer; if 'referrer' is
        True (default), send the current URL as the referrer; if 'referrer'
        is a false value, send no referrer.  If 'charset' is given, it
        overrides any received 'charset' parameter; setting 'charset' to RAW
        leaves the content undecoded in an 8-bit string.  If the document is
        successfully fetched, return a Region spanning the entire document.
        Any relevant previously stored cookies will be included in the
        request, and any received cookies will be stored for future use.i-  i.  t   locationR   i   (   i-  i.  (   RQ   R   R   R7   R   R   t   resolvet   TrueR   RR   R9   R]   R   R   R0   t   Region(   R   RQ   R8   t	   redirectsRS   R}   t   historyentry(    (    s   ./scrape.pyt   go  s"    * 
c         C   s:   |  i  i   \ |  _ |  _ |  _ |  _ |  _ |  _ |  i S(   s>   Restore the state of this session before the previous request.(   R   t   popRQ   R   R   R7   R   R   (   R   (    (    s   ./scrape.pyt   back,  s    3c         C   sr   | p |  i  i d d | } | p t d |   n | i d d  p t d |   n |  i | d  S(   s   Find the first link that has the given anchor text, and follow it.
        The anchor may be given as a string or a compiled RE.  If 'region' is
        specified, only that region is searched for a matching link, instead
        of the whole document.t   aR   s   link %r not foundt   hrefR   s   link %r has no href(   R   t   firstR   R   R   (   R   t   anchort   regiont   link(    (    s   ./scrape.pyt   follow2  s    c   	      K   s<  | i  d j o | p | i d  } | p t d |   n | d j	 o | i   } n
 | i } d | j o | i d d  | | d <n | i |  | d i   p d } | p | i d |  i	  } | d j o% |  i
 | d	 t |  d |  Sn5 | d
 j o |  i
 | | |  Sn t d |   d S(   sN  Submit a form, optionally by clicking a given button.  The 'region'
        argument can be the form itself or a button in the form to click.
        Obtain the parameters to submit by (a) starting with the 'paramdict'
        dictionary if specified, or the default parameter values as returned
        by get_params; then (b) adding or replacing parameters in this
        dictionary according to the keyword arguments.  The 'url' argument
        overrides the form's action attribute and submits the form elsewhere.
        After submission, follow redirections up to 'redirects' times.t   forms   %r is not contained in a formR;   R<   R   R4   R   t   actionRp   t   posts   unknown form method %rN(   t   tagnamet	   enclosingR   R   t   copyR   R   t   updateRz   RQ   R   RM   (	   R   R   t	   paramdictRQ   R   R   R   t   pR4   (    (    s   ./scrape.pyt   submit>  s     	&	%c         C   sE   |  i  o7 | i d  p | i d  o t |  i  |  } n | S(   s3   Resolve a URL with respect to the current location.s   http://s   https://(   RQ   R\   R   (   R   RQ   (    (    s   ./scrape.pyR   Z  s    
!c         C   sX   t  |  i  \ } } } } } | i d  d i d  d } t |  i | | g  d S(   s   Put a cookie in this session's cookie jar.  'cookieline' should
        have the format "<name>=<value>; domain=<domain>; path=<path>".R   iR   i    N(   R   RQ   R   Rl   R]   (   R   t
   cookielineR3   R5   R6   R~   R   (    (    s   ./scrape.pyt	   setcookiea  s     N(   R   R   t   __doc__R   R   R   R   R   R   R   R   R   (    (    (    s   ./scrape.pyR      s   

!		s7   (('[^']*'|"[^"]*"|--([^-]+|-[^-]+)*--|-(?!-)|[^'">-])*)c         C   s   d |  t  d S(   Nt   <t   >(   t   tagcontent_re(   t
   tagname_re(    (    s   ./scrape.pyt   tag_rel  s    s   (\?|!\w*|/?[a-zA-Z_:][\w:.-]*)s!   &(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?c         C   sB   t  |   t j o
 t } n
 d   } | d  } t i | |   S(   s'   Decode HTML entities in the given text.c         S   s$   |  d  j o t  |   p
 t |   S(   i   (   t   unichrt   chr(   R<   (    (    s   ./scrape.pyt   <lambda>{  s    c         S   s   |  i  d  } | i d  o | t | d d   SnU | i d  o | t | d   Sn- | t j o | t |  Sn |  i  d  Sd  S(   Ni   s   #xi   i   t   #i    (   t   groupR\   R(   R   (   R   t   uchrt   entity(    (    s   ./scrape.pyt   entitydecode|  s    (   t   typet   unicodeR   t
   charrefpatt   sub(   RE   R   R   (    (    s   ./scrape.pyt
   htmldecodev  s
    
	
c         C   sL   |  i  d d  }  |  i  d d  }  |  i  d d  }  |  i  d d  }  |  S(	   sA   Use HTML entities to encode special characters in the given text.t   &s   &amp;t   "s   &quot;R   s   &lt;R   s   &gt;(   R
   (   RE   (    (    s   ./scrape.pyt
   htmlencode  s
    c         c   s)   x" |  ] } t  |  d  | f Vq Wd S(   s   %%%02XN(   R   (   t   .0R   (    (    s   ./scrape.pys	   <genexpr>  s   	 i   c         c   s   x |  ] } | | f Vq Wd  S(   N(    (   R   t   c(    (    s   ./scrape.pys	   <genexpr>  s   	 t   ABCDEFGHIJKLMNOPQRSTUVWXYZt   abcdefghijklmnopqrstuvwxyzs   0123456789._-c         C   s   d i  t t i |    S(   NR   (   R   t   mapt	   urlquotedR   (   RE   (    (    s   ./scrape.pyt   urlquote  s    c         C   s\   g  } |  i    D]5 \ } } | d t |  t |  i d d  f q ~ } d i |  S(   Ns   %s=%ss   %20t   +R   (   R   R   R
   R   (   R   R=   R`   R<   Rj   (    (    s   ./scrape.pyRM     s    Hc         C   s   |  i  d d  i  d d  S(   Nt   (s   (?:s   (?:?s   (?(   R
   (   R   (    (    s   ./scrape.pyt	   no_groups  s    s   (p|table|form)s   (div|br|tr)s   <(!\s*--|style\b|script\b)s   --\s*>t   !s   </script[^>]*>t   scripts   </style[^>]*>t   stylec      	   C   s  g  d } } x t  i |  |  } | p Pn | i d  i d  i   } | i   i d  } t | i |  | i    } | p Pn | i	 |  | | i
   ! | i   } q | i	 |  |  d i |  }  g  } xt i |   D] } g  } x t i |  D]x }	 d i t i |	   }	 t |	  }	 t |	  t j o d p d }
 |	 i |
 d  }	 | i	 d i |	 i     qWd	 i |  } t |  t j o. y | i d
  Wq| i d  } qXn | i	 |  q Wt i d d d i |   i   S(   s   Strip HTML tags from the given string, yielding line breaks for DIV,
       BR, or TR tags and blank lines for P, TABLE, or FORM tags.i    i   R   s   utf-8R   u    s   R   s   
t   asciis   latin-1s   

+s   

(   t   cdatapatRw   R   R+   Re   Rz   t   encodet   endcdatapatRy   R0   Rx   R   t   parasplitterR   t   linesplittert   tagsplitterR   R   R   R
   R!   R|   R   R   (   t   htmlRC   t   post
   startmatchR   t   endmatcht
   paragraphst	   paragraphRh   Ri   t   nbsp(    (    s   ./scrape.pyt	   striptags  sB        s0   \s*([\w:.-]+)(\s*=\s*('[^']*'|"[^"]*"|[^\s>]*))?c         C   s   h  } d } x t  i |  |  } | p Pn | i   } | i d  | i d  p d } } | d  d j o | d d !} n y t |  } Wn n Xy t |  } Wn n Xt |  | | i   <q | S(	   s?   Turn a string of name=value pairs into an attribute dictionary.i    i   i   R   RD   R   i(   RD   R   (   t   attrpatRw   Ry   R   R!   R   Rz   (   RE   Rk   R   R   R;   R<   (    (    s   ./scrape.pyt
   parseattrs  s(    &c         C   s   d  S(   i   (    (   t   x(    (    s   ./scrape.pyR     s    c         C   s
   |  i    S(    (   Re   (   R   (    (    s   ./scrape.pyR     s    c         C   s$   y t  |   d SWn d Sn Xd  S(   Ni   i    (   t	   getnumber(   R   (    (    s   ./scrape.pyt   NUMERIC  s
    
c         C   sJ   t  | d  o | i |   Sn& t |  o | |   Sn |  | j Sd S(   s;   Match a string specimen to a desired string or compiled RE.R   N(   R.   R   t   callable(   t   speciment   desired(    (    s   ./scrape.pyt   matchcontent  s
    c         C   s   x | i    D]v \ } } | i d  i d d  } | t j o | |  j o d Sq q | |  j o t |  | |  p d Sq q Wd S(   s  Match an attribute dictionary to a dictionary of desired attribute
    values, where each value can be a string or a compiled RE.  For
    convenience, the keys of the dictionary have their underscores turned
    into hyphens, and trailing underscores are removed.t   _R   i    i   (   R   R+   R
   t   MISSINGR   (   R   R   R;   R<   (    (    s   ./scrape.pyt
   matchattrs   s     !R   c           B   s  e  Z d  Z d d% d% d% d  Z d   Z d   Z d   Z d   Z g  d d  Z	 d% g  d d  Z
 e d	    Z e d
    Z d   Z d   Z e e  Z e e  Z d   Z e e  Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d d  Z d d  Z d   Z d% d  Z d% d  Z  d% d  Z! d% d  Z" d% d  Z# d% d  Z$ d% d% g  d  Z% d% d% g  d   Z& d% d% g  d!  Z' d% d% g  d"  Z( d% d% g  d#  Z) d% d% g  d$  Z* RS(&   s  A Region object represents a contiguous region of a document (in terms
    of a starting and ending position in the document string) together with
    an associated HTML or XML tag and its attributes.  Dictionary-like access
    retrieves the name-value pairs in the attributes.  Various other methods
    allow slicing up a Region into subregions and searching within, before,
    or after a Region for tags or elements.  For a Region that represents a
    single tag, the starting and ending positions are the start and end of
    the tag itself.  For a Region that represents an element, the starting
    and ending positions are just after the starting tag and just before the
    ending tag, respectively.i    c   	      C   s  t  | t  o" | |  _ |  i |  i  |  _ n | i |  _ | i |  _ | d j o t |  i  } n | | |  _ |  _ d h  |  _	 |  _
 | | |  _ |  _ | d j	 o) |  i | \ |  _ |  _ |  _	 |  _
 n | d j	 o- |  i | d |  i | d |  _ |  _ n | o& | o | d | d |  _ |  _ n t |  i  d |  _ |  _ x t |  i  D]r \ } \ } } } } | |  i j o | |  i j  o | |  _ n | |  i j o | |  i j o | |  _ qlqlWd S(   sb  Create a Region.  The 'parent' argument is a string or another
        Region.  The 'start' and 'end' arguments, if given, are non-negative
        indices into the original string (not into the parent region).  The
        'starttag' and 'endtag' arguments are indices into an internal array
        of tags, intended for use by the implementation only.i   i    iN(   RL   t
   basestringt   documentt   scantagst   tagsR   R/   Rx   Ry   R   Rk   t   starttagt   endtagt   tagmint   tagmaxR	   (	   R   t   parentRx   Ry   R   R   R   R   Rk   (    (    s   ./scrape.pyR     s.    	)-   c         C   sz   |  i  oX d i g  } |  i i   D] } | d | q$ ~  } d |  i |  i |  i  | f Sn d |  i |  i f Sd  S(   NR   s    %s=%rs   <Region %d:%d %s%s>s   <Region %d:%d>(   R   R   Rk   R   Rx   Ry   (   R   R=   t   itemRk   (    (    s   ./scrape.pyt   __repr__?  s
    
7c         C   s   |  i  S(   N(   R   (   R   (    (    s   ./scrape.pyt   __str__G  s    c   	      C   s   g  } d } x t  i | |  } | p Pn | i   \ } } | i d  i   i d  } | i d  } | i | | | | g  | d	 j oU t | i | |  } | p Pn | i   \ } } | i | | d | d g  n | } q | S(
   s.   Generate a list of all the tags in a document.i    i   s   utf-8i   R   R   R    R   (   R   R   (   t   tagpatRw   t   spanR   Rz   R   R0   R   (	   R   R   R   R   R   Rx   Ry   R   Rk   (    (    s   ./scrape.pyR   K  s$    !	c         C   s   |  i  | d |  i  | d } } | d  d	 j o | | j p | d j oj t | t  oI | d  d
 j o h  |  i  | d <} q t |  |  i  | d <} n t | |  Sq n d S(   sA   Return 1 if the ith tag matches the given tagname and attributes.i   i   i   R   R    Rp   R   N(   R   R    (   Rp   R   (   R   R   RL   R   R   R   (   R   R   R   Rk   t   itagnamet   iattrs(    (    s   ./scrape.pyt   matchtag`  s    #c         C   s(  t  | t  o | i   } n |  i | d } d } x t | d t |  i   D] } |  i | d d | j o | d 8} n | d j p% | d j o\ |  i | d | j oD | o | |  i j o | Sn | o | |  i j o | Sn Pn |  i | d | j o | d 7} qT qT Wd S(   s  Find the index of the tag that ends an element, given the index of
        its start tag, by scanning for a balanced matching end tag or a tag
        whose name is in 'enders'.  'enders' may contain plain tag names (for
        start tags) or tag names prefixed with '/' (for end tags).  If
        'outside' is 0, scan within the current region; if 'outside' is 1,
        scan starting from the end of the current region onwards.i   i   R    i    N(   RL   R   R   R   t   rangeR/   R   (   R   R   t   enderst   outsideR   t   depthR   (    (    s   ./scrape.pyt
   findendtagl  s      2c         C   s   |  i  | | |  } | d j	 o\ |  i | d |  i | d } } | d j p  t t |  i | | ! |  o | Sq~ n d S(   s  If the element with the given start tag matches the given content,
        return the index of the tag that ends the element.  The end of the
        element is found by scanning for either a balanced matching end
        tag or tag whose name is in 'enders'.  'enders' may contain plain tag
        names (for start tags) or tag names prefixed with '/' (for end tags).
        If 'outside' is 0, scan within the current region; if 'outside' is 1,
        scan starting from the end of the current region onwards.i   i    N(   R   R   R   R   R   R   (   R   R   R   R   R   R   Rx   Ry   (    (    s   ./scrape.pyt   matchelement  s    #c         C   s   |  i  |  i |  i !S(    (   R   Rx   Ry   (   R   (    (    s   ./scrape.pyR     s    c         C   s   t  |  i  S(    (   R   R   (   R   (    (    s   ./scrape.pyR     s    c   	   	   C   s  |  i  d j oh  } x |  i d  D] } d | j on d | j oa | i d d  i   } | d j p | d j o+ d | j o | i d d  | | d <q q& q& Wx |  i d  D] } d | j o g  } | i d  D]" } d | j o | | d q q ~ } d | j o | | | d <qM| o | d | | d <qMq q Wx9 |  i d  D]( } d | j o | i | | d <qaqaW| Sn d S(   s?   Get a dictionary of default values for all the form parameters.R   t   inputR;   t   disabledR   RE   t   passwordt   hiddent   checkboxt   radiot   checkedR<   R   t   selectt   optiont   selectedt   multiplei    t   textareaN(   s   textR  R  (   R  R  (   R   t   alltagsR   Rz   t   allR   (	   R   R   R   R   R  R=   R  t
   selectionsR  (    (    s   ./scrape.pyt
   get_params  s0     & % c         C   s   |  i  d j o g  } |  i d  D]( } | d i   d	 j o | | q$ q$ ~ g  } |  i d  D]( } | d i   d
 j o | | qf qf ~ Sn d S(   s.   Get a list of all the form submission buttons.R   R   R   R   t   imaget   buttonR   N(   s   submitR  (   s   submitR   (   R   R  Rz   (   R   R=   t   tagt   _[2](    (    s   ./scrape.pyt   get_buttons  s
    (c         C   s   t  |  i  S(   N(   R   RE   (   R   (    (    s   ./scrape.pyt
   get_number  s    c         C   s   | |  i  j S(   N(   Rk   (   R   R;   (    (    s   ./scrape.pyt   __contains__  s    c         C   s]   t  | t  o |  i | i | i  Sn | |  i j o |  i | Sn t d |   d  S(   Ns   no attribute named %r(   RL   t   slicet   __getslice__Rx   t   stopRk   t   AttributeError(   R   R;   (    (    s   ./scrape.pyt   __getitem__  s
    c         C   s#   | |  i  j o |  i  | Sn | S(   N(   Rk   (   R   R;   t   default(    (    s   ./scrape.pyR     s    c         C   s   |  i  i   S(   N(   Rk   t   keys(   R   (    (    s   ./scrape.pyR    s    c         C   s   |  i  |  i S(   N(   Ry   Rx   (   R   (    (    s   ./scrape.pyt   __len__  s    c         C   s   | d  j o
 d } n | d  j o t |   } n t | d  o | i } n, | d j  o | |  i 7} n | |  i 7} t | d  o | i } n, | d j  o | |  i 7} n | |  i 7} t |  t |  i |  t |  i |   S(   Ni    Ry   Rx   (   R   R/   R.   Ry   Rx   R   t   maxt   min(   R   Rx   Ry   (    (    s   ./scrape.pyR    s    
c         C   s   t  |  |  i  S(   s3   Return the Region for everything after this Region.(   R   Ry   (   R   (    (    s   ./scrape.pyt   after  s    c         C   s   t  |  d |  i  S(   s4   Return the Region for everything before this Region.i    (   R   Rx   (   R   (    (    s   ./scrape.pyt   before  s    c         C   s   t  | d  o> | i |  i  } | o! |  | i |  | i |  !Sq n9 |  i i |  } | d j o |  | | t |  !Sn t d |   d S(   s   Search this Region for a string or a compiled RE and return a
        Region representing the match.  If 'group' is given, it specifies
        which grouped subexpression should be returned as the match.Rw   is   no match found for %rN(   R.   Rw   R   Rx   Ry   t   findR/   R   (   R   t   targetR   R   Rx   (    (    s   ./scrape.pyR#    s    %c         C   s   d } |  i  } g  } t | d  oQ x | i | |  } | p Pn | i |  \ } } | i |  | | ! q( nO xK | i | |  } | d j  o Pn | t |  } | i |  | | ! qy | S(   sw   Search this Region for a string or a compiled RE and return a
        sequence of Regions representing all the matches.i    Rw   (   R   R.   Rw   R   R0   R#  R/   (   R   R$  R   R   R   t   matchesR   Rx   (    (    s   ./scrape.pyt   findall  s"    	c         C   s   d } |  i  } g  } t | d  oh xP | i | |  } | p Pn | i d  \ } } | i |  | | ! | } q( | i |  |  nf xQ | i | |  } | d j  o Pn | t |  } | i |  | | ! | } q | i |  |  | S(   s   Find all occurrences of the given string or compiled RE and use
        them as separators to split this Region into a sequence of Regions.i    Rw   (   R   R.   Rw   R   R0   R#  R/   (   R   t	   separatorR   R   R%  R   Rx   Ry   (    (    s   ./scrape.pyR     s*    			c         K   s   xN t  |  i |  i d  D]3 } |  i | | |  o t |  d d |  Sq q W| d j o d p d | } | o d | p d } t d | | f   d S(	   so   Return the Region for the first tag entirely within this Region
        with the given tag name and attributes.i   i    R  s   <%s> tags    matching %rR   s   no %s found%sN(   R   R   R   R   R   R   R   (   R   R   Rk   R   R  R   (    (    s   ./scrape.pyt   firsttag6  s     c         K   s   xQ t  |  i |  i d d  D]3 } |  i | | |  o t |  d d |  Sq q W| d	 j o d p d | } | o d | p d } t d | | f   d	 S(
   sn   Return the Region for the last tag entirely within this Region
        with the given tag name and attributes.i   ii    R  s   <%s> tags    matching %rR   s   no %s found%sN(   R   R   R   R   R   R   R   (   R   R   Rk   R   R  R   (    (    s   ./scrape.pyt   lasttag@  s     c         K   sd   g  } xW t  |  i |  i d  D]< } |  i | | |  o  | i t |  d d |   q  q  W| S(   su   Return a list of Regions for all the tags entirely within this
        Region with the given tag name and attributes.i   i    (   R   R   R   R   R0   R   (   R   R   Rk   R   R   (    (    s   ./scrape.pyR  J  s     $c         K   s   |  i    i | |  S(   sr   Return the Region for the nearest tag after the end of this Region
        with the given tag name and attributes.(   R!  R(  (   R   R   Rk   (    (    s   ./scrape.pyt   nexttagS  s    c         K   s   |  i    i | |  S(   su   Return the Region for the nearest tag before the start of this
        Region with the given tag name and attributes.(   R"  R)  (   R   R   Rk   (    (    s   ./scrape.pyt   previoustagX  s    c         K   sY   g  d } } x4 |  i  | |  D]  } | i |  | | ! | } q  W| i |  |  | S(   sq   Split this Region into a list of the subregions separated by tags
        with the given tag name and attributes.i    (   R  R0   (   R   R   Rk   t
   subregionsRx   R  (    (    s   ./scrape.pyt   splittag]  s     
c   
      K   s   xw t  |  i |  i d  D]\ } |  i | | |  o@ |  i | | |  } | d	 j	 o t |  d d | |  Sqv q q W| d	 j o d p d | } | o d | p d } | d	 j	 o d | p d }	 t d | | |	 f   d	 S(
   s  Return the Region for the first element entirely within this Region
        with the given tag name, content, and attributes.  The element ends at
        a balanced matching end tag or any tag listed in 'enders'.  'enders' may
        may contain plain tag names (for start tags) or tag names prefixed with
        '/' (for end tags).  The element content is passed through striptags()
        for comparison.  If 'content' has a match() method, the stripped content
        is passed to it; otherwise it is compared directly as a string.i   i    t   elements   <%s> elements    matching %rR   s    with content %rs   no %s found%s%sN(   R   R   R   R   R   R   R   R   (
   R   R   R   R   Rk   R   R   R  R   R   (    (    s   ./scrape.pyR   h  s     "c   
      K   s   xz t  |  i |  i d d  D]\ } |  i | | |  o@ |  i | | |  } | d
 j	 o t |  d d | |  Sqy q q W| d
 j o d p d | } | o d | p d } | d
 j	 o d | p d }	 t d	 | | |	 f   d
 S(   s   Return the Region for the last element entirely within this Region
        with the given tag name, content, and attributes.  The element ends at
        a balanced matching end tag or at any tag listed in 'enders'.i   ii    R.  s   <%s> elements    matching %rR   s    with content %rs   no %s found%s%sN(   R   R   R   R   R   R   R   R   (
   R   R   R   R   Rk   R   R   R  R   R   (    (    s   ./scrape.pyt   lastz  s     "c         K   s   g  } |  i  } x | |  i j ow |  i | | |  oS |  i | | |  } | d j	 o- | i t |  d d | |   | d } q n | d 7} q W| S(   s   Return Regions for all non-overlapping elements entirely within
        this Region with the given tag name, content, and attributes, where
        each element ends at a balanced matching end tag or any tag listed
        in 'enders'.i    i   N(   R   R   R   R   R   R0   R   (   R   R   R   R   Rk   t   elementsR   R   (    (    s   ./scrape.pyR    s    	 c         K   s   |  i    i | | | |  S(   s   Return the Region for the nearest element after the end of this
        Region with the given tag name, content, and attributes.  The element
        ends at a balanced matching end tag or any tag listed in 'enders'.(   R!  R   (   R   R   R   R   Rk   (    (    s   ./scrape.pyt   next  s    c         K   s   |  i    i | | | |  S(   s   Return the Region for the nearest element before the start of this
        Region with the given tag name, content, and attributes.  The element
        ends at a balanced matching end tag or any tag listed in 'enders'.(   R"  R/  (   R   R   R   R   Rk   (    (    s   ./scrape.pyt   previous  s    c         K   s  |  i  o |  i o |  i  d } n |  i d } xv t | d d  D]b } |  i | | |  oF |  i | | | d d } | d j	 o t |  d d | |  Sq qE qE W| d j o d p d | } | o d | p d }	 | d j	 o d	 | p d }
 t d
 | |	 |
 f   d S(   s   Return the Region for the nearest element that encloses this Region
        with the given tag name, content, and attributes.  The element ends at
        ends at a balanced matching end tag or any tag listed in 'enders'.i   iR   i    R.  s   <%s> elements    matching %rR   s    with content %rs   no %s found%s%sN(	   R   R   R   R   R   R   R   R   R   (   R   R   R   R   Rk   t   laststarttagR   R   R  R   R   (    (    s   ./scrape.pyR     s     "N(+   R   R   R   R   R   R   R   R   R   R   R   t   propertyR   RE   R  R  R   t   buttonsR  t   numberR  R  R   R  R  R  R!  R"  R#  R&  R   R(  R)  R  R*  R+  R-  R   R/  R  R1  R2  R   (    (    (    s   ./scrape.pyR     sN   
$																

	c         C   s   t  |   i   S(   sB   Read and return the entire contents of the file at the given path.(   RO   R1   (   R6   (    (    s   ./scrape.pyR1     s    c         C   s*   t  |  d  } | i |  | i   d S(   s1   Write the given text to a file at the given path.t   wN(   RO   R-   t   close(   R6   RE   RB   (    (    s   ./scrape.pyR-     s    c         C   s   d d k  } | i t |    S(   s?   Return the deserialized contents of the file at the given path.iN(   t   marshalt   loadRO   (   R6   R9  (    (    s   ./scrape.pyR:    s    c         C   s9   d d k  } t |  d  } | i | |  | i   d S(   sB   Serialize the given data and write it to a file at the given path.iNR7  (   R9  RO   t   dumpR8  (   R6   R8   R9  RB   (    (    s   ./scrape.pyR;    s    c         C   s|   xe t  |   i d d  i d d  i   D]9 } y t |  SWq+ y t |  SWqd q+ qd Xq+ Xq+ Wt d |    d S(   s   Find and parse an integer or floating-point number in the given text,
       ignoring commas, percentage signs, and non-numeric words.t   ,R   t   %R   s   no number found in %rN(   R   R
   R   R(   t   floatR   (   RE   t   word(    (    s   ./scrape.pyR     s    + (A   R   t
   __author__R   R
   t   __date__t   __version__t   urlparseR   R   t   htmlentitydefsR   R%   R   R   R   t	   ExceptionR   R:   RF   R   RY   Ra   Rl   t   objectR{   R   R   R   R   t	   anytag_reR   R   R   R   R   Rf   R   R   R   R   RM   R   R   t   IR   R   R   R   R   t   attr_reR   R   R   t   PRESENTt   ANYR   R   R   R   R1   R-   R:  R;  R   Rt   (    (    (    s   ./scrape.pys   <module>'   sr   	
				
	\u						!!	)								 					