大家经常使用Python3的urllib库进行get请求,得到数据,来封装爬虫的行为。下面封装了一个方法供大家参考使用:
这里比较规范的使用了工程化的思想,考虑了日志的编写;爬虫发送get请求时,则考虑了UA等http request head部分的设置;并且支持代理服务器的信息处理;返回的状态码不是200时的处理;并且考虑了超时问题,及网页的编码问题
import sys
import logging
import urllib
import random
import time
import socket
timeout = 15
socket.setdefaulttimeout(timeout)#这里对整个socket层设置超时时间。后续文件中如果再使用到socket,不必再设置
# 创建日志的实例
logger = logging.getLogger("basicSpider")
# 定制Logger的输出格式
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
# 创建日志:文件日志,终端日志
file_handler = logging.FileHandler('basicSpider.log')
file_handler.setFormatter(formatter)
consle_handler = logging.StreamHandler(sys.stdout)
consle_handler.setFormatter(formatter)
# 设置默认的日志级别
logger.setLevel(logging.INFO)
# 把文件日志和终端日志添加到日志处理器中
logger.addHandler(file_handler)
logger.addHandler(consle_handler)
PROXY_RANGE_MIN = 1
PROXY_RANGE_MAX = 10
PROXY_RANGE = 10
NUM = 10
def downloadHtml(url, headers=[],
proxy={}, num_retries=NUM,
timeout=NUM, decodeInfo="utf-8"):
"""
爬虫的get请求,考虑了UA等http request head部分的设置;
支持代理服务器的信息处理;
返回的状态码不是200,这时怎么处理;
考虑超时问题,及网页的编码问题
"""
html = None
if num_retries <= 0:
return html
# 一般来说,使用UA池和Proxy池相结合的方式来访问某个页面,会
#更加的不容易被反爬。
# 动态的调整代理服务器的使用策略
if random.randint(PROXY_RANGE_MIN,PROXY_RANGE_MAX) > PROXY_RANGE:
logger.info("No Proxy")
proxy = None
proxy_handler = urllib.request.ProxyHandler(proxy)
# 替换handler,以实现可以处理Proxy
opener = urllib.request.build_opener(proxy_handler)
# 把opener装载进urllib库中,准备使用
opener.addheaders = headers
urllib.request.install_opener(opener)
try:
response = urllib.request.urlopen(url)
html = response.read().decode(decodeInfo)
except UnicodeDecodeError:
logger.error("UnicodeDecodeError")
except urllib.error.URLError or \
urllib.error.HTTPError as e:
logger.error("urllib error %s"%e.__str__)
if hasattr(e,'code') and 400 <= e.code < 500:
logger.error("Client Error %d"%e.code) # 客户端问题,通过分析日志来跟踪
elif hasattr(e,'code') and 500 <= e.code < 600:
html = downloadHtml(url,
headers,
proxy,
timeout,
decodeInfo,
num_retries-1)
time.sleep(PROXY_RANGE)# 休息的时间可以自己定义一个策略
except Exception as e:
logger.error("Download error reson is %s"%e.reson)
urllib.request.close()#记得要关闭
return html
if __name__ == "__main__":
url = "http://www.sina.com.cn"
headers = [("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36")] # 注意:这里的UA和Proxy可以根据自己的需求来改变,也可以对它们使用池来随机取值
proxy = {"http":"182.129.243.84:9000"}
print(downloadHtml(url, headers, proxy))
logger.removeHandler(file_handler)
logger.removeHandler(consle_handler)