Python分布式爬虫前菜(1):关于静态动态网页内容获取的N种方法

来源:互联网 发布:xp升级 软件 编辑:程序博客网 时间:2024/06/05 11:37

爬虫是我们快速获取需要的数据的一个非常有效的途径,而爬虫的第一步便是能够请求远方服务器为我们返回所需的网页信息。我们知道,正常情况下在浏览器上我们只要输入正确的统一资源定位器url,即网页地址便可轻松打开我们想要看到页面。同理,在设计python爬虫程序时,我们也可以调用对应的库通过参数设置来连接网络处理http协议。针对静态的网页,常常被使用到的库有urllib, urllib2, requests等等,通过它们可以很方便的请求服务器返回特定地址的网页内容。但是如果遇到JS加载的动态网页,用前面的方法往往收不到我们想要的结果。这时候就可以召唤出强大的自动化测试工具Selenium并喊上它的小伙伴PhantomJS来一起升级打怪了。

(一) urllib, urllib2,直接上例子:

import urllib2response = urllib2.urlopen("http://www.baidu.com")print response.read()

上面只要给一个url,例如百度,调用urllib2库便可以单枪匹马读到这个网址对应的网页源码,代码特别简洁。实际爬虫中由于考虑到对方的反爬虫机制,网络响应时间或者发送请求需要添加额外的信息 ,我们需要多添加几行代码,目的是让服务器尽量相信收到的请求都是来自正常的访问对象。为了程序逻辑清晰,我们可以为urlopen设计一个request对象作为传入参数,例如:

import urllibimport urllib2#添加urlurl = 'xxx'request = urllib2.Request(url)#为了模拟浏览器行为,伪装对方识别问题,可以添加Headers属性,例如下面的agent便是设置请求身份:user_agent = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'headers = { 'User-Agent' : user_agent}request = urllib2.Request(url, headers)#有时访问某些网站需要提供一些信息,例如用户名和密码,这时可以这样:values = {"username":"yourname","password":"????"}data = urllib.urlencode(values)request = urllib2.Request(url, data, headers)  #在遇到网络状况不好时可以设置timeout来设置等待多久超时response = urllib2.urlopen(request,timeout=18)print response.read()

更多的相关内容可以查看这个urllib和urllib2。

(二)requests,一款简单美观而友好的外部库。

requests所有的功能都可以通过以下7个方法访问。它们全部都会返回一个response对象的实例。

#创建并发送一个requestrequests.request(method, url, **kwargs)参数:method -- method for the new Request object.url -- URL for the new Request object.params -- (optional) Dictionary or bytes to be sent in the query string for the Request.data -- (optional) Dictionary, bytes, or file-like object to send in the body of the Request.json -- (optional) json data to send in the body of the Request.headers -- (optional) Dictionary of HTTP Headers to send with the Request.cookies -- (optional) Dict or CookieJar object to send with the Request.files -- (optional) Dictionary of 'name': file-like-objects (or {'name': file-tuple}) for multipart encoding upload. file-tuple can be a 2-tuple ('filename', fileobj), 3-tuple ('filename', fileobj, 'content_type') or a 4-tuple ('filename', fileobj, 'content_type', custom_headers), where 'content-type' is a string defining the content type of the given file and custom_headers a dict-like object containing additional headers to add for the file.auth -- (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.timeout (float or tuple) -- (optional) How long to wait for the server to send data before giving up, as a float, or a (connect timeout, read timeout) tuple.allow_redirects (bool) -- (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.proxies -- (optional) Dictionary mapping protocol to the URL of the proxy.verify -- (optional) whether the SSL cert will be verified. A CA_BUNDLE path can also be provided. Defaults to True.stream -- (optional) if False, the response content will be immediately downloaded.cert -- (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.#例如:import requestsurl='xxxx'headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}proxies = { 'http' : '127.0.0.1:8118'}response=requests.request('GET',url, timeout=20, proxies=proxies, headers=headers)返回类型requests.Response另:#发送一个HEAD request.requests.head(url, **kwargs)#发送一个GET requestrequests.get(url, params=None, **kwargs)#发送一个POST requestrequests.post(url, data=None, json=None, **kwargs)#发送一个PUT requestrequests.put(url, data=None, **kwargs)#发送一个PATCH requestrequests.patch(url, data=None, **kwargs)#发送一个DELETE requestrequests.delete(url, **kwargs)
更详细的介绍可以参考官网requests。

(三)Selenium + PhantomJs,高效处理动态网页的完美组合。

我们使用前面的方法可以单纯的获取网页的html代码,如若是遇到要经过JS渲染的网页内容时则会变得非常麻烦。所以我们需要能够像浏览器一样处理要JS渲染的页面的工具,而PhantomJs正是一款基于WebKit的无界面的网页交互工具,其提供的JavaScript API可以实现自动化浏览、截屏等浏览器功能。Selenium是一款自动化测试工具,其支持Firefox,Chrome,Safari等主流的浏览器,借助selenium就可以模拟人类的各种网页操作行为,例如打开浏览器,输入信息,点击,翻页等等。PhantomJS作为一款无界面的浏览器,Selenium会对它感冒吗?答案是非常感冒,因为PhantomJs不仅能完成浏览器的功能,其效率相对来说还更高。例如:

from selenium import webdriverfrom selenium.webdriver.common.keys import Keysphantomjs_path = '/data/opt/brew/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs'driver = webdriver.PhantomJS(executable_path=phantomjs_path)url = 'xxxx'driver.get(url)#轻松得到到JS渲染页面的源码page_source = driver.page_source.encode('utf8')
有时候我们需要做到页面交互,即可以模拟人在浏览器上点击,输入,鼠标移动等各种行为时,这就需要先做到对页面元素的定位问题。其中WebDriver提供了多种方法来实现元素定位:

#定位一个元素的方法有find_element_by_idfind_element_by_namefind_element_by_xpathfind_element_by_link_textfind_element_by_partial_link_textfind_element_by_tag_namefind_element_by_class_namefind_element_by_css_selector#定位多元素,返回一个list,方法有find_elements_by_namefind_elements_by_xpathfind_elements_by_link_textfind_elements_by_partial_link_textfind_elements_by_tag_namefind_elements_by_class_namefind_elements_by_css_selector#例如有如下网页源码:<html> <body>  <form id="loginForm">   <input name="username" type="text" />   <input name="password" type="password" />   <input name="continue" type="submit" value="Login" />   <input name="continue" type="button" value="Clear" />  </form></body><html>#form可以这样来定位login_form = driver.find_element_by_id('loginForm')#username&password两个元素定位如下username = driver.find_element_by_name('username')password = driver.find_element_by_name('password')#如果使用xpath来定位username,以下方法都okusername = driver.find_element_by_xpath("//form[input/@name='username']")username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]")username = driver.find_element_by_xpath("//input[@name='username']")
更多内容可以参考selenium_python,PhantomJS。

这篇文章简短介绍了网页源码内容获取的各种方法,包括静态网页常常使用到的urllib,urllib2,requests和动态网页使用到的selenium,phantomjs组合。在爬虫过程中,我们往往需要提取并保留网页中有用的信息,所以接下来要介绍的是如何针对获得的网页源码提取出有用信息的工作。




7 0