写在前面
当我们想要获取一个网页的数据时,比较简便的方式是调用requests.get()
这个方法,初次使用你会觉得很简单很神奇,但是这里面到底进行了什么操作,你是否又知道呢?当你整明白了这些之后,你就可以设计一个调度器去调度请求,这样在你学Scrapy的时候会有更深的理解
解析过程
我们先来看看requests的get方法中实现了什么
def get(url, params=None, **kwargs):
kwargs.setdefault('allow_redirects', True)
return request('get', url, params=params, **kwargs)
从上面可以看到,kwargs
是设置一个http
请求所需要的参数。get
方法先设置一下allow_redirects
参数,这个参数是指明在请求的时候是否允许重定向,True
表示允许。然后调用request
方法。那这个方法又实现了什么呢?
def request(method, url, **kwargs):
# By using the 'with' statement we are sure the session is closed, thus we
# avoid leaving sockets open which can trigger a ResourceWarning in some
# cases, and look like a memory leak in others.
with sessions.Session() as session:
return session.request(method=method, url=url, **kwargs)
这个方法先创建一个Session
对象,然后调用Session的request方法,把request
方法中传入的参数作为参数调用。看到这里就可以知道,对同一个站点,使用requests.get()
请求该站点的不同页面的时候,这两个请求是独立的(简单理解就是第一个请求模拟登录了该网站,然后第二个请求去访问有登录限制的页面会出现Error),因为每次调用就会生成一个Session对象,维持一次会话。当你模拟登录某网站的时候,你再去访问带有登录限制的网页的时候,会自动带上有登录成功后服务器返回给你的Cookies,这个时候就可以正常访问。
我们接着看
def request(self, method, url,
params=None,
data=None,
headers=None,
cookies=None,
files=None,
auth=None,
timeout=None,
allow_redirects=True,
proxies=None,
hooks=None,
stream=None,
verify=None,
cert=None,
json=None):
# Create the Request.
req = Request(
method = method.upper(),
url = url,
headers = headers,
files = files,
data = data or {},
json = json,
params = params or {},
auth = auth,
cookies = cookies,
hooks = hooks,
)
prep = self.prepare_request(req)
proxies = proxies or {}
settings = self.merge_environment_settings(
prep.url, proxies, stream, verify, cert
)
# Send the request.
send_kwargs = {
'timeout': timeout,
'allow_redirects': allow_redirects,
}
send_kwargs.update(settings)
resp = self.send(prep, **send_kwargs)
return resp
根据一个请求的参数(超时,代理,url,重定向等)构建一个Request
对象,初始化请求参数,然后调用一下prepare_request
方法,这个又是啥?再定位到该方法
def prepare_request(self, request):
cookies = request.cookies or {}
# Bootstrap CookieJar.
if not isinstance(cookies, cookielib.CookieJar):
cookies = cookiejar_from_dict(cookies)
# Merge with session cookies
merged_cookies = merge_cookies(
merge_cookies(RequestsCookieJar(), self.cookies), cookies)
# Set environment's basic authentication if not explicitly set.
auth = request.auth
if self.trust_env and not auth and not self.auth:
auth = get_netrc_auth(request.url)
p = PreparedRequest()
p.prepare(
method=request.method.upper(),
url=request.url,
files=request.files,
data=request.data,
json=request.json,
headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict),
params=merge_setting(request.params, self.params),
auth=merge_setting(auth, self.auth),
cookies=merged_cookies,
hooks=merge_hooks(request.hooks, self.hooks),
)
return p
prepare_request
实现的其实是根据传过来的Request
对象,提出出该请求的相关参数,然后构建出一个PreparedRequest
对象,初始化该对象,最后返回一个PreparedRequest
实例
再回到request
方法,在前面的操作完成之后,最后调用了send
方法,把PreparedRequest
对象发出去,然后这个方法会返回一个response响应。至此,对get()
方法的分析就告一段落了
说了那么多其实也就是下图所示流程
总结
了解了requests的请求过程,我们就可以利用这个东西去做一个爬虫的请求队列,这样就可以多个Spider共享,也算是是为分布式抓取开了个头吧