爬虫基础
我们可以把互联网比作一张大网,而爬虫(即网络爬虫)便是在网上爬行的蜘蛛。把网的节点比作一个个网页,爬虫爬到这就相当于访问了该页面,获取了其信息。可以把节点的连线比作网页与网页之间的链接关系,这样蜘蛛通过一个节点后,可以顺着节点连线继续爬行到下一个节点,即通过一个网页继续获取后续的网页,这样整个网的节点便可以被蜘蛛全部爬行到,网站的数据就可以被抓取下来了。
为什么学习爬虫
为了装x
爬虫概述
简单来说,爬虫就是获取网页并提取和保存信息的自动化程序
获取网页
爬虫首先要做的就是爬取网页,这里就是获取网页的源代码,源代码里包含了网页的部分有用信息,所以只要把源代码获取下来,就可以从中提取想要的信息了。
提取信息
获取网页源代码后,接下来就是分析网页源代码,从中提取我们想要的数据。
- 首先,最通用的方法就是采用正则表达式提取,这是一个万能的方法,但是在构造正则表达式时比较复杂且容易出错
- 另外由于网页的结构有一定的规则,所以还有一些根据网页节点属性、CSS选择器或XPath来提取网页信息的库,如
BeautifulSoup,pyquery,lxml 等。使用这些库,我们可以高效快速地从中提取网页信息,如节点的属性、文本值等
提取信息是爬虫非常重要的部分,它可以使复杂的数据变得条理清晰,以便我们后续处理和分析数据。
保存数据
提取信息后,我们一般会将提取到的数据保存到某处以便后续使用。这里保存形式有多种多样,如可以简单保存为txt文本或 json 文本,也可以保存到数据库,如 MySQL 和 MongoDB 等,也可以保存至远程服务器,如借助SFTP进行操作等
自动化程序
说到自动化程序,意思是说爬虫可以代替人来完成这些操作。首先,我们手工当然可以提取到这些信息,但是当量特别大或者想快速获取大量数据的话,肯定还是要借助程序。爬虫就是代替我们来完成这份爬取工作的自动化程序,它可以在抓取过程中进行各种异常处理、错误重试等草垛,确保爬取持续高效的运行。
能爬取怎样的数据
在网页中我们能看到各种各样的信息,最常见的便是常规网页,它们对应着HTML代码,而最常抓取的便是HTML源代码
另外,可能有些网页返回的不是HTML代码,而是一个JSON字符串(其中API接口大多采用这样的形式),这种格式的数据方便传输和解析,它们同样可以抓取,而且数据提取更方便
此外,我们还可以看到各种二进制数据,如图片、视频和音频等。利用爬虫,我们可以将这些二进制数据抓取下来,最后保存成对应的文件名。
另外,还可以看到各种扩展名的文件,如CSS、JavaScript和配置文件等,这些其实也是最普通的文件,只要在浏览器里面可以访问到,就可以将其抓取下来
上述内容其实都对应各自的URL,是基于HTTP或HTTPS协议的,只要是这种数据,爬虫都可以抓取
对于爬虫来说,用于爬虫爬取速度过快,在爬取过程中可能遇到同一个IP访问过于频繁的问题,此时网站就会让我们输入验证码登录或者直接封锁IP,这样会给爬取带来机打的不便
使用代理隐藏真实的IP,让服务器误以为是代理服务器在请求自己。这样在爬取过程中通过不断更换代理,就不会被封锁,可以达到很好的爬取效果
urllib
urllib
urllib库,是Python内置的HTTP请求库,不需要额外安装,它包含如下四个模块
request :它是最基本的HTTP请求模块,可以用来模拟发送请求。就像在浏览器里输入网址一样,只需要给库方法传入URL以及额外的参数,就可以模拟实现这个过程了
error :异常处理模块,如果出翔请求错误,我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止
parse :一个工具模块,提供了许多URL处理方法,比如拆分,解析,合并等
rebotparser :主要是用来识别网站的robots.txt文件,然后判断哪些网站不可以爬,用得比较少
发送请求
使用urllib的request模块,我们可以方便的实现请求发送并得到响应,
urlopen
urllib.request模块提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还带有处理授权验证(authentication)、重定向(redirect)、浏览器Cookies以及其他内容
基本使用
import urllib.request
response = urllib.request.urlopen('https://www.python.org')
html = response.read().decode('utf-8')
print(type(response)) # <class 'http.client.HTTPResponse'>
它是一个HTTPResponse类型的对象,主要包含read、readinto、getheader、getheaders、fileno等方法,以及msg、version、status、reason、debuglevel、closed等属性
调用 read 方法可以得到返回的网页内容,调用 status 属性可以得到返回结果的状态码, 200 代表请求成功,404 代表网页未找到等。
import urllib.request
response = urllib.request.urlopen('https://www.python.org')
print(response.status)
print(response.getheaders())
print(response.getheader('Server')) # 得到以下结果
200
[('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'),
('X-Clacks-Overhead', 'GNU Terry Pratchett'), ('Content-Length', '47397'), ('Accept-Ranges', 'bytes'),
('Date', 'Mon, 01 Aug 2016 09:57:31 GMT'), ('Via', '1.1 varnish'), ('Age', '2473'), ('Connection', 'close'),
('X-Served-By', 'cache-lcy1125-LCY'), ('X-Cache', 'HIT'), ('X-Cache-Hits', '23'), ('Vary', 'Cookie'),
('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]
nginx
前两个分别输出了相应的状态码和头信息,最后一个输出通过调用getheader方法并传递一个参数Server获取了响应头中的Server值,结果是Nginx,意思是服务器是用Nginx搭建的
利用最基本的urlopen方法,可以完成最基本的简单网页的GET请求抓取
参数
urllib.request.urlopen(url, data=None, [timeout,]*, cafile=None, capath=None, cadefault=False, context=None)
1、data参数
data参数是可选的。如果要添加改参数,需要使用bytes方法将参数转化为字节流编码格式的内容,即bytes类型。另外,如果传递了这个参数,则它的请求方式就不再是GET请求,而是POST请求
import urllib.parse
import urllib.request
data = bytes(urllib.parse.urlencode({
'word': 'hello'}), encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())
这里我们传递了一个参数 word,值是 hello。它需要被转码成 bytes(字节流)类型。其中转字节流采用了 bytes 方法,该方法的第一个参数需要是 str(字符串)类型,需要用 urllib.parse 模块里的 urlencode 方法来将参数字典转化为字符串;第二个参数指定编码格式,这里指定为 utf8。
在这里请求的站点是 httpbin.org,它可以提供 HTTP 请求测试,本次我们请求的 URL 为:http://httpbin.org/post,这个链接可以用来测试 POST 请求,它可以输出 Request 的一些信息,其中就包含我们传递的 data 参数
2、timeout参数
timeout参数用于设置超时时间,单位为秒,意思就是如果请求超出了设置的这个时间,还没有得到响应,就会抛出异常。如果不指定该参数,就会使用全局默认时间。它支持HTTP、HTTPS、FTP请求
import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)
print(response.read())
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "/var/py/python/urllibtest.py", line 4, in <module> response =
urllib.request.urlopen('http://httpbin.org/get', timeout=1)
...
urllib.error.URLError: <urlopen error timed out>
这里我们设置超时时间是1秒,程度一秒过后,服务器依然没有响应,于是抛出了URLError异常。该异常属于urllib.error模块,错误原因是超时。因此我们可以使用异常处理
3、其他参数
除了data参数和timeout参数外,还有context参数,它必须是ssl.SSLContext类型,用来指定SSL设置
此外,cafile和capath这两个参数分别制定CA证书和它的路劲,