一、引言与前期准备
1.1 深入了解一个网站的方法
检查robots.txt(了解抓取该网站时存在哪些限制)
检查sitemap(一般在robots.txt中能找到,这里提供了该网站的所有网页的链接)
估算网站大小(一个简便方法是检查Google爬虫的结果 -> site:www.baidu.com)
识别网站所用技术(python中的builtwith方法 -> builtwith.parse("www.baidu.com") )
寻找网站所有者(whois查询:站长或者python中的 -> print(whois.whois("www.baidu.com")) )
1.2 网页访问error异常问题
在访问网页时,有时遇到网页访问出错(可能请求错误、可能服务端错误)从而为导致无法正常下载网页,因此我们要能健壮地捕获访问过程的错误并作出相应处理。这里转载一篇python3中的urllib.error实现:
Python3网络爬虫(三):urllib.error异常。自己根据这篇文章及实际python3中遇到的问题成功实现了正常捕获网页访问error异常。以下代码实现两个功能:遇到5xx错误重试下载;设置用户代理
#此代码实现并测试爬取下载网页中的几个问题或方法:遇到5xx错误重试下载;设置用户代理
import urllib.request
import urllib.error
def download(url, user_agent = "brain", num_retries = 2): #下载网页
print("downloading:",url)
header = {"user-agent": user_agent} #设置用户代理,而不使用python默认的用户代理Python-urllib/3.6
req = urllib.request.Request(url, headers = header)
try:
html = urllib.request.urlopen(req).read()
except urllib.error.URLError as e: #下载过程中出现问题
print("download error:",e.reason)
html = None
if num_retries > 0: #错误4XX发生在请求存在问题,而5XX错误则发生在服务端存在问题,所以在发生5XX错误时重试下载
if hasattr(e, "code") and 500<= e.code <600:
return download(url, user_agent, num_retries-1) # recursively retry 5XX HTTP errors
return html
#download("http://example.webscraping.com") #访问正常
download("http://httpstat.us/500") #这个网页测试用,一直是5XXerror
运行结果:
downloading: http://httpstat.us/500
download error: Internal Server Error
downloading: http://httpstat.us/500
download error: Internal Server Error
downloading: http://httpstat.us/500
download error: Internal Server Error
二、爬取网站
爬取网站,我们通常需要做两件事:下载网页(该过程一般称为爬取 crawling);提取数据(或保存数据,或继续分析数据等)
2.1 下载网页(爬取 crawling)
三种爬取网站的常见方法:爬取网站地图、遍历每个网页的数据库ID、跟踪网页链接
2.1.1 爬取网站地图sitemap中的url链接(使用正则表达式)
#def download()实现并测试爬取下载网页中的几个问题或方法:遇到5xx错误重试下载;设置用户代理
#def crawl_sitemap(url)实现爬取一个网站sitemap中url数据(用到正则表达式),并且将每个url下载
import urllib.request
import urllib.error
import re
def download(url, user_agent = "brain", num_retries = 2): #下载url网页
print("downloading:",url)
header = {"user-agent": user_agent} #设置用户代理,而不使用python默认的用户代理Python-urllib/3.6
req = urllib.request.Request(url, headers = header)
try:
html = urllib.request.urlopen(req).read()
except urllib.error.URLError as e: #下载过程中出现问题
print("download error:",e.reason)
html = None
if num_retries > 0: #错误4XX发生在请求存在问题,而5XX错误则发生在服务端存在问题,所以在发生5XX错误时重试下载
if hasattr(e, "code") and 500<= e.code <600:
return download(url, user_agent, num_retries-1) # recursively retry 5XX HTTP errors
return html
#download("http://example.webscraping.com") #访问正常
#download("http://httpstat.us/500") #这个网页测试用,一直是5XXerror
def crawl_sitemap(url): ##爬取一个网站sitemap中url,此url为网站sitemap的url
sitemap = download(url) # download the sitemap file
sitemap = str(sitemap) #把bytes类型转成str类型,以便下面用正则表达式提取数据
links = re.findall("<loc>(.*?)</loc>", sitemap) # extract the sitemap links这里用了正则表达式,返回的是结果列表
for link in links:
html = download(link) #把爬取的url都下载下来
crawl_sitemap("http://example.webscraping.com/sitemap.xml")
2.1.2 ID遍历爬虫
我们无法完全依靠文件提供的url链接,当结果不符合预期(sitemap本身提供的链接有问题)或需求有变时,我们将不再依赖sitemap而转而利用网站结构的弱点更加轻松地访问所有内容。
http://example.webscraping.com/view/Brazil-3
http://example.webscraping.com/view/ Australia-2
可以看出上述url只在结尾处有区别,包括国家名和ID。一般情况下,web服务器会忽略这个字符串,只使用ID来匹配数据库中的相关记录。因此下面我们将其移除,加载:http://example.webscraping.com/view/3,测试发现链接可用能正常打开。因此现在我们忽略页面别名而直接使用ID来下载所有国家的页面
#def download()实现并测试爬取下载网页中的几个问题或方法:遇到5xx错误重试下载;设置用户代理
#def crawl_sitemap(url)实现爬取一个网站sitemap中url数据(用到正则表达式),并且将每个url下载
import urllib.request
import urllib.error
import re #正则表达式
import itertools #使用ID遍历
def download(url, user_agent = "bra