爬虫异常处理与浏览器伪装初步

爬虫的异常处理

如果一个爬虫没有进行异常处理,那么在爬虫遇到异常时就会直接崩溃停止运行。下次再运行时就会从头开始。因此,想要开发一个具有顽强生命力的爬虫,必须要进行异常处理。

常见状态码及含义

  • 301 Moved permanently:重定向到新的URL,永久性

  • 302 Found:重定向到临时的URL,非永久性

  • 304 Not modified:请求的资源未更新

  • 400 Bad Request:非法请求

  • 401 Unauthorized:请求未经授权

  • 403 Forbidden:禁止访问

  • 404 Not found:没有找到对应页面

  • 500 Internal server error:服务器内部出现错误

  • 501 Not Implemented:服务器不支持实现请求所需要的功能

URLError与HTTPError

这两者都是异常处理的类,HTTPError是URLError的子类,HTTPError有异常状态码与异常原因,URLError没有异常状态码。所以在处理异常的时候,不能使用URLError直接代替HTTPError。如果要代替,必须判断是否有状态码属性。

URLError出现的原因可能有以下几个:

  1. 无法连接服务器
  2. 远程的URL不存在
  3. 本地没有网络
  4. 触发了HTTPError子类

爬虫的浏览器伪装技术

在爬取一些网站的时候会返回403,因为对方服务器会对爬虫进行屏蔽。此时我们需要伪装成浏览器才能够爬取。浏览器伪装一般是通过报头Headers来进行。在Headers中的关键字段为User-Agent字段。

例如我们在爬取csdn的博文的时候:

1
2
3
4
5
6
7
8
9
10
import urllib.request

url = 'https://blog.csdn.net/qq_26442553/article/details/96108475'
headers = ('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36')
opener = urllib.request.build_opener()
opener.addheaders = [headers]
data = opener.open(url).read()
fp = open('blog.html', 'wb')
fp.write(data)
fp.close()

就使用了headers变量来储存我们的报头信息,这个报头信息可以在打开任意一个网页的时候的网站响应信息中找到。

新闻爬虫小例子

需求:将新浪新闻首页(https://news.sina.com.cn)的所有新闻爬到本地。

思路:先爬首页,通过正则获所有新闻链接,然后依次爬取各个新闻并储存到本地。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import urllib.error
import urllib.request
import re

url = 'https://news.sina.com.cn'
headers = ('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15')
opener = urllib.request.build_opener()
opener.addheaders = [headers]
top_page_data = opener.open(url).read()
top_page_data = top_page_data.decode('utf-8', 'ignore')

pattern = 'href="(https://news.sina.com.cn/.*?)"'
all_url = re.compile(pattern).findall(top_page_data)
for i in range(len(all_url)):
try:
print('this is the ' + str(i) +'-th scrapy')
this_url = all_url[i]
this_file = 'sinanews/'+str(i)+'.html'
urllib.request.urlretrieve(this_url, this_file)
print('---------------success------------')
except urllib.error.URLError as e:
if hasattr(e, 'reason'):
print(e.reason)