3 @copyright: (c) 2005 by Szoftver Messias Bt.
6 Objects of the MozillaEmulator class can emulate a browser that is capable of:
10 - configurable user agent string
12 - multipart POST (send files)
13 - receive content into file
16 I have seen many requests on the python mailing list about how to emulate a browser. I'm using this class for years now, without any problems. This is how you can use it:
19 2. Install and open the livehttpheaders plugin
20 3. Use the website manually with firefox
21 4. Check the GET and POST requests in the livehttpheaders capture window
22 5. Create an instance of the above class and send the same GET and POST requests to the server.
26 - For testing, use a MozillaCacher instance - this will cache all pages and make testing quicker
27 - You can change user agent string in the build_opened method
28 - The "encode_multipart_formdata" function can be used alone to create POST data from a list of field values and files
38 socket.setdefaulttimeout(10)
41 class MozillaEmulator(object):
43 def __init__(self, cacher=None, trycount=0):
44 """Create a new MozillaEmulator object.
46 @param cacher: A dictionary like object, that can cache search results on a storage device.
47 You can use a simple dictionary here, but it is not recommended.
48 You can also put None here to disable caching completely.
49 @param trycount: The download() method will retry the operation if it fails. You can specify -1 for infinite retrying.
50 A value of 0 means no retrying. A value of 1 means one retry. etc."""
54 self.cookies = cookielib.LWPCookieJar()
56 self.trycount = trycount
58 def build_opener(self, url, postdata=None, extraheaders=None, forbid_redirect=False):
59 if extraheaders is None:
63 'Accept': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png',
64 'Accept-Language': 'en,en-us;q=0.5',
65 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
67 for key, value in extraheaders.iteritems():
68 txheaders[key] = value
69 req = urllib2.Request(url, postdata, txheaders)
70 self.cookies.add_cookie_header(req)
72 redirector = HTTPNoRedirector()
74 redirector = urllib2.HTTPRedirectHandler()
76 http_handler = urllib2.HTTPHandler(debuglevel=self.debug)
77 https_handler = urllib2.HTTPSHandler(debuglevel=self.debug)
79 u = urllib2.build_opener(
82 urllib2.HTTPCookieProcessor(self.cookies),
87 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.8) Gecko/20050511 Firefox/1.0.4'
89 if not postdata is None:
90 req.add_data(postdata)
93 def download(self, url, postdata=None, extraheaders=None, forbid_redirect=False,
94 trycount=None, fd=None, onprogress=None, only_head=False):
95 """Download an URL with GET or POST methods.
97 @param postdata: It can be a string that will be POST-ed to the URL.
98 When None is given, the method will be GET instead.
99 @param extraheaders: You can add/modify HTTP headers with a dict here.
100 @param forbid_redirect: Set this flag if you do not want to handle
101 HTTP 301 and 302 redirects.
102 @param trycount: Specify the maximum number of retries here.
103 0 means no retry on error. Using -1 means infinite retring.
104 None means the default value (that is self.trycount).
105 @param fd: You can pass a file descriptor here. In this case,
106 the data will be written into the file. Please note that
107 when you save the raw data into a file then it won't be cached.
108 @param onprogress: A function that has two parameters:
109 the size of the resource and the downloaded size. This will be
110 called for each 1KB chunk. (If the HTTP header does not contain
111 the content-length field, then the size parameter will be zero!)
112 @param only_head: Create the openerdirector and return it. In other
113 words, this will not retrieve any content except HTTP headers.
115 @return: The raw HTML page data, unless fd was specified. When fd
116 was given, the return value is undefined.
118 warnings.warn("Performing download of %s" % url, UserWarning, 2)
120 if extraheaders is None:
123 trycount = self.trycount
127 req, u = self.build_opener(url, postdata, extraheaders, forbid_redirect)
128 openerdirector = u.open(req)
130 print req.get_method(), url
131 print openerdirector.code, openerdirector.msg
132 print openerdirector.headers
133 self.cookies.extract_cookies(openerdirector, req)
135 return openerdirector
136 return openerdirector.read()
137 except urllib2.URLError:
139 if (trycount > -1) and (trycount < cnt):
143 print "MozillaEmulator: urllib2.URLError, retryting ", cnt
146 class HTTPNoRedirector(urllib2.HTTPRedirectHandler):
147 """This is a custom http redirect handler that FORBIDS redirection."""
149 def http_error_302(self, req, fp, code, msg, headers):
150 e = urllib2.HTTPError(req.get_full_url(), code, msg, headers, fp)
151 if e.code in (301, 302):
152 if 'location' in headers:
153 newurl = headers.getheaders('location')[0]
154 elif 'uri' in headers:
155 newurl = headers.getheaders('uri')[0]