正则表达式(regular expression)是提取数据时常用的方法,其解析网页的速度比BeautifulSoup库更快。python提供了相关re。
'''
用于提取百度首页中的与百度相关的链接及名称
'''
import re
import requests
from fake_useragent import UserAgent
url = 'https://www.baidu.com/'
ua = UserAgent()
headers = {'User-Agent': ua.random}
html = request.get(url, headers=headers)
html.encoding = 'utf-8'
html = html.text
titles = re.findall(r'<a href="(http://.*?.com)" name="tj_tr.*?" class="mnav">(\w{2})</a>', html)
print(titles)
有时,程序获得的html内容可以和浏览器看到的并不一致。
具体来说就是,浏览器检查元素看到的内容和网页源码(ctrl+u查看源码)
是一致的,但是代码获取的内容却不一致,这可能是请求头的问题,
可以尝试修改请求头再次获取。所以应在解析网页前先打印网页内容查看是否一致,
findall提供参数:第一个是正则表达式,第二个是带检索的字符串。(1)findall根据正则表达式在字符串里找到所有满足条件的字符串,并将所有结果存储到列表中,之后返回此列表。(2)在正则表达式中为一些字符加上括号,表示想要提取的数据就是括号里面的内容,也就是findall返回的内容。多个括号可以一次提取多个数据,以元祖的形式放在一起。(3)开头字母r,为了避免转义,即不讲正则表达式内的 ‘ \ ‘当作是转义字符。
In [3]: import re
In [4]: string = 'hello\\data\\world'
In [5]: re.findall('\\\\(\w+)\\\\', string)
Out[5]: ['data']
In [6]: re.findall(r'\\(\w+)\\', string)
Out[6]: ['data']
(4).? :‘ . ‘ 在一般情况下表示匹配除了换行符以为的任意字符,当find all中的flag指定为re.DOTALL时,其可以匹配所有字符,包括换行符。‘ ‘表示匹配任意个数的字符,包括0个。‘ ? ‘表示开启非贪婪模式匹配,即尽可能匹配短的字符串。
(5)\w:匹配Unicode字符,一般包括大小写字母,数字和下划线。{2}:表示同时出现两次前面的字符才能匹配。
In [7]: string = 'hello'
In [8]: re.findall('l{2}', string)
Out[8]: ['ll']
In [9]: re.findall('l', string)
Out[9]: ['l', 'l']
小结:BeautifulSoup和正则表达式都是解析网页的工具。前者使用方法简单,且稳定性较强,但是解析速度较慢;后者解析速度快,匹配精确,但是使用方法复杂,稳定性差。
import re
import time
import chardet
import urllib.robotparser
from fake_useragent import UserAgent
def get_headers():
ua = UserAgent()
user_agent = ua.random
headers = {'User-Agent': user_agent}
return headers
#获取代理IP的函数直接给出了proxies
#也可以用此函数去爬取免费的代理IP
def get_proxies(url ):
proxies = {
"http": "125.88.74.122:84"
}
return proxies
def get_data(url, num_retries=3, proxies=None):
try:
data = requests.get(url, timeout=5, headers=headers)
print(data.status_code)
except requests.exceptions.ConnectionError as e:
print("请求错误, url", url)
print("错误详情:", e)
data = None
except:
print("未知错误, url", url)
data = None
if (data != None) and (500 <= data.status_code < 600):
if(num_retries > 0):
print("服务器出错,正在重连...")
time.sleep(1)
num_retries -= 1
get_data(url, num_retries, proxies=proxies)
return data
def parse_data(data):
if data==None:
return None
charset = chardet.detect(data.content)
data.encoding = charset['encoding']
html_text = data.text
'''
对网页数据进行解析提取等操作,假设这里要获取网页的title
'''
interesting_data = re.findall('<title>(.*?)</title>', html_text)
return interesting_data
if '__name__' == '__main__':
url = "http://www.baidu.com"
headers = get_headers()
#此处不是重点,如果运行不出可以注释此语句
proxies = get_proxies()
data = get_data(url, num_retries=3, proxies=proxies)
interesting_data = parse_data(data)
print(interesting_data)
至此,爬虫添加了异常处理,编码检测,服务器错误重链,动态UA和代理IP功能。