爬虫: requests, Beautiful Soup, 正则
requests库:请求
robots.txt:爬虫排除标准
Beautiful Soup:解析HTML页面
re:正则表达式
Scrapy框架
IDE
IDLE:自带
SublimeText:专业
Wing:调试功能,多人开发
Visual Studio & PTVS, PyCharm
数据分析,科学计算:Canop, Anaconda
Request库
r = requests.request(url, params=None, **kwargs)
Request——Response
1. Response属性:
status_code:200表示成功
text,url
encoding:如果header中不存在charset,则认为ISO-8859-1
apparent_encoding:备选编码(内容分析)
content:二进制形式,response.content.decode('utf-8')
代替text
2. 异常:
ConnectionError:连接错误
HTTPError
URLRequired:url缺失
TooMuchRedirects:重定向异常
ConnectTimeout:连接超时
Timeout:超时
r.raise_for_status()
, 不是200则引发HTTPError异常
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return "产生异常"
3. HTTP协议:超文本传输协议,请求与相应模式,无状态协议,URL作为标识
操作:GET, HEAD, POST, PUT, PATCH, DELETE
URL:http://host[:post][path]
,存取资源的Internet路径,对应数据资源
host:主机域名或IP
port:端口号,缺省端口80
path:路径
**kwargs参数 | 说明 |
---|---|
params | 字典、字节序列,作为参数增加到url中 |
data | 字典、字节序列、文件对象,作为Request的内容POST |
json | JSON格式的数据,作为Request的内容 |
headers | 字典,HTTP定制头,模拟浏览器 |
cookies | 字典,CookieJar,Request中的cookie |
auth | 元组,支持HTTP认证功能 |
files | 字典类型,传输文件 |
timeout | 设定超时时间,秒为单位 |
proxies | 字典类型,设定访问代理服务器,可以增加登录认证(防追踪) |
allow_redirects | True/False,重定向开关 |
stream | 获取内容立即下载开关,True/False |
verify | 认证SSL证书开关,True/False |
cert | 本地SSL证书路径 |
属性:‘r.request.’ + headers,url
request.get(url, params=None, **kwargs)
request.head(url, **kwargs)
request.post(url, data=None,json=None, **kwargs)
request.put(url, data=None, **kwargs)
request.patch(url, data=None, **kwargs)
局部修改
request.delete(url, **kwargs)
协议
-
问题
规模:
小规模,网页 Requests
中规模,网站,系列网站,Scrapy
大规模,定制开发,全网
限制:来源审查(User-Agent),Robots协议
-
Robots协议
在根目录:/robots.txt
User-agent: * Disallow: /
遵守方式:爬虫自动识别或先看看(类人行为可考虑不遵守)
import requests
url = 'https://www.amazon.cn/gp/product/B01M8L5Z2Y'
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print('Fail')
# 错误分析
r.encoding = r.apparent_encoding
r.request.headers
# 假装是个浏览器
import requests
url = 'https://www.amazon.cn/gp/product/B01M8L5Z2Y'
try:
kv = {'user-agent': 'Mozilla/5.0'}
r = requests.get(url, headers=kv)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print('Fail')
浏览器关键词
import requests
kw = {'wd':'python'}
kv = {'user-agent': 'Mozilla/5.0'}
r = requests.get('http://www.baidu.com/s', params=kw, headers=kv)
r.status_code
r.request.url
图片爬取:确定文件格式
import requests
path = r'C:\Users\Desktop'
url = 'https://cdn.sspai.com/2020/04/19/cb225d96e4a20faf87aff067f83f2268.png'
r = requests.get(url)
r.status_code
with open(path, 'wb') as f:
f.write(r.content)
f.close()
ip归属地址查询:
import requests
url = 'http://m.ip138.com/ip.asp?ip='
ip = '...'
r = requests.get(url + ip)
r.status_code
# 不行就改一下headers
HTML解析器:Beautiful Soup
HTML解析库:
BeautifulSoup解析器 | 使用方法 | 条件 |
---|---|---|
bs4的HTML解析器 | BeautifulSoup(mk, ‘html.parser’) | bs4 |
lxml的HTML解析器 | BeautifulSoup(mk, ‘lxml’) | lxml |
lxml的XML解析器 | BeautifulSoup(mk, ‘xml’) | lxml |
html5lib的解析器 | BeautifulSoup(mk, ‘html5lib’) | html5lib |
pip install beautifulsoup4
from bs4 import BeautifulSoup
soup = BeautifulSoup(r.text, 'html.parser')
print(soup.prettify())
soup.a
返回a标签,多个标签只返回第一个
解析器:
解析器 | 使用方法 | 特点,要求 |
---|---|---|
python标准库 | BeautifulSoup(r.text, ‘html.parser’) | python内置,容错能力强 |
lxml HTML | BeautifulSoup(r.text, ‘lxml’) | 要求按照C语言,容错能力强,速度块 |
lxml XML | BeautifulSoup(r.text, [‘lxml’, ‘xml’]) | 要求按照C语言,支持XML |
html5lib | BeautifulSoup(r.text, ‘html5lib’) | 容错能力最强,浏览器方式解析 |
基本元素:
BeautifulSoup的基本元素 | 说明 |
---|---|
Tag | 最基本的信息组织单位,<>和</>开头和结尾 |
Name | <p>, 'p’就是名字,<tag>.name ,<tag>.parent.ame
|
Attributes | <p class=’…’>的class=’…’,属性,字典形式,<tag>.attrs
|
NavigableString | <>…</>中的…,非属性字符串<tag>.string ,strings(子孙)生成器形式,stripped_strings非空白字符,get_text子孙,不是列表形式 |
Comment | 注释部分 |
-
内容遍历方法
-
下行遍历:contents(子),迭代:children(子),descendants(子孙所有)
-
上行遍历:parent(父),迭代:parents(所有先辈)
-
平行遍历(同一个父标签):next_sbling, previous_sibling,
迭代:next_sblings, previous_siblings
得到的不一定是标签类型
-
# head标签的子标签
soup.head.contents
# 子标签数目
len(soup.head.contents)
# 第二个子标签
soup.head.contents[1]
# 上行遍历
soup = BeautifulSoup(r.text, 'html.parser')
for parent in soup.parents:
if parent is None:
print(parent) #soup本身
else:
print(parent.name)
信息标记的三种形式
HTML:通过<>…</>标签形式组织不同类型的信息
XML:和HTML类似,标签为主(基于HTML)(internet交互)
<name>...</name>
, <name />
, <!-- -->
JASON:键值对,字符时:键值都要有“”(代码一部分,但无注释)
"key":"value"
, "key":["value1", "value2"]
, "key":{"subkey":"subvalue"}
YAML:无类型键值对,无“”,缩进表达所属,并列前-,整块|,注释#(配置文件)
key:value
, key:#Comment
信息提取方法:遍历、直接搜索关键信息,(和re同用)
融合:例如:提取HTML中所有URL:找到所有a标签,解析提取href链接内容
1. find_all(name, attrs, recursive, string, **kwargs,limit)
attrs属性,recursive子孙默认True,string字符串,limit获取几个
简写形式:
<tag>(..)
= <tag>.find_all(..)
soup(..)
= soup.find_all(..)
扩展方法:
<>.find()
:只返回一个结果
<>.find_parents()
:返回先辈列表。<>.find_parent()
<>.find_next_siblings()
,<>.find_next_sibling()
<>.find_previous_siblings()
,<>.find_previous_sibling()
for link in soup.find_all('a'):
print(link.get('href'))
from bs4 import BeautifulSoup
html="""
...
"""
soup = BeautifulSoup(html, 'lxml')
# 1.获得所有tr
tr = soup.find_all('tr')
# 2.第二个tr
tr2 = soup.find_all('tr', limit =2)[1]
# 3.class=even的tr,class_以便做区分,不然报错
tr_even = soup.find_all('tr', class_='even')
# 4.id='test',class='test'的tr,也可attrs={}
tr_22 = soup.find_all('tr', id='test', class_='text')
# 5.所有tr的href属性
trs = soup.find_all('tr')
for tr in trs:
tr_href = tr['href']
# 或者
tr_href_2 =tr.attrs['href']
# 6.所有tr纯文本
trs = soup.find_all('tr')
for tr in trs:
tr_info = list(tr.strings) #所有非标签字符串,其他应用string
2. select
css选择器:必需记住的选择符
p{…}对标签p定样式
# 标签名查找
print(soup.select('a'))
# 类名查找,class='sister'
print(soup.select('.sister'))
#查id,在id前加#,id='link1'
print(soup.select('#link1'))
# 组合查找,空格分开,或者,子标签>分隔
#不能同时提取id和class
print(soup.select('p #link1'))
print(soup.select(’'head > title'))
# 属性查找
print(soup.select('a[herf="..."]'))
3. 正则
# 正则
import re
for tag in soup.find_all(re.compile('b')):
print(tag.name)
soup.find_all(True) # 所有标签
# 含有course属性的p标签
soup.find_all('p', 'course')
#含有id='link1'属性的标签
soup.find_all(id='link1')
实例:爬取大学排名
1. 获取网页内容:getHTMLText()
2. 提取信息到适当的数据结构:fillUnivList()
3. 展示输出结果:printUnivList()
from bs4 import BeautifulSoup
import bs4
import requests
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ''
def fillUnivList(ulist, html):
soup = BeautifulSoup(html, 'html.parser')
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag): # 是否是标签
tds = tr('td')
ulist.append([tds[0].string, tds[1].string, tds[3].string])
def printUnivList(ulist, num):
tplt = "{0:^10}\t{1:{3}^12}\t{2:^10}"
print(tplt.format('排名', '学校名称', '总分', chr(12288)))
for i in range(num):
u = ulist[i]
print(tplt.format(u[0], u[1], u[2], chr(12288)))
def mian():
uinfo = []
url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20)
mian()
中文对齐问题:chr(12288)
正则:re库
常用函数
raw string类型(不包含转义符):r'text'
, r'[1-9]\d{5}'
re库常用功能函数 | 说明 |
---|---|
re.search() | 第一个位置,返回match对象(在一个字符串中) |
re.match() | 开始位置器匹配,返回match(在一个字符串中) |
re.findall() | 所有匹配的,列表返回全部字符串 |
re.split() | 按匹配结果分割,返回列表(在一个字符串中) 参数maxsplit=0最大分割数 |
re.finditer() | 搜索字符串,返回匹配结果的迭代,match对象 |
re.sub() | 替换,(在一个字符串中) 参数:repl:替换的,count=0几次。prt |
re.search(pattern, string, flags=0)
pattern正则,string目标,flags控制标记
flags标记:re.i
, re.IGNORECASE
:忽略大小写
re.M
, re.MULTILINE
:^匹配每行开始
re.S
, re.DOTALL
:. 匹配所有字符
re.compile(pattern, flags=0)
:字符串编译成正则表达式
import re
match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
print(match.group(0)) #match对象:输出匹配字符段group(0)
# 面向对象用法
pat = re.compile(r'[1-9]\d{5}')
rst = pat.search('BIT 100081')
# 匹配\\n: re.search('\\\\n', text)
# 匹配\c:re.search(r '\\c', text)
match对象
属性:string待匹配文本,re(pattern对象),pos搜索开始位置,endpos搜索结束位置
常用方法:**group(0)**匹配后的字符串,**start()**搜索开始位置,**end()**搜索结束位置,**span()**返回(start和end)
group:等价group(0),整个满足条件的字符串
groups:子组,索引从1开始
group(1):第一个子组 (子组:())
贪婪匹配:默认最长子串,加?表非贪婪
最小匹配操作符 | 说明 |
---|---|
*? | 0或无限次扩展 |
+? | 前一个字符,1+ |
?? | 前1,(0|1) |
{m,n}? | 前1,m-n次 |
实例:淘宝搜索
-
循环获取页面
-
对于每个页面,提取信息
-
输出
headers获取:
1.登录淘宝,进入搜索页,F12
2.选择Network,刷新一下,找到最上方以search?开头的文件,右键 3.选择copy,copy as cURL(bush)
4.在https://curl.trillworks.com/,粘贴到curl command窗口
5.复制右侧的headers内容,以变量header保存,作为参数传给requests.get
import re
import requests
def getHTMLText(url):
header = {
'...'
}
try:
r = requests.get(url, timeout=30, headers = header)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
print('Fail')
return ''
def parsePage(ilt, html): #查看源代码,找tag
try:
plt = re.findall(r'"view_price":"[\d.]*"', html)
tlt = re.findall(r'"raw_title":".*?"', html)
for i in range(len(plt)):
price = eval(plt[i].split(':')[1]) #去最外层引号
title = eval(tlt[i].split(':')[1])
ilt.append([title,price])
except:
print("")
def printGoodsList(ilt):
tplt = '{:4}\t{:16}\t{:8}'
print(tplt.format("序号", "名称", "价格"))
count=0
for g in ilt:
count += 1
print(tplt.format(count, g[0], g[1]))
def main():
goods = "鼠标"
depth = 2
start_url = 'https://s.taobao.com/search?q=' + goods
infoList = []
for i in range(depth):
try:
url = start_url + '&s=' + str(44*i)
html = getHTMLText(url)
parsePage(infoList, html)
except:
continue
printGoodsList(infoList)
if __name__ == '__main__':
main()
实例:股票爬虫requests-bs4-re
-
名称和交易信息,保存到文件(新浪股票,百度股票)
-
选取原则:静态存在与HTML页面,非js代码生成,无robots限制,F12查看
-
设计:获取列表—逐个获取信息—存储(字典)!更改http://app.finance.ifeng.com/list/stock_cate.php?c=E48
上一篇: oracle用户创建及权限设置
下一篇: requests_模拟登录知乎
推荐阅读
-
基础爬虫,谁学谁会,用requests、正则表达式爬取豆瓣Top250电影数据!
-
Python爬虫实战之Requests+正则表达式爬取猫眼电影Top100
-
Python爬虫学习==>第十章:使用Requests+正则表达式爬取猫眼电影
-
python3 爬虫笔记(一)beautiful_soup
-
小白学 Python 爬虫(21):解析库 Beautiful Soup(上)
-
python requests 正则爬虫
-
爬虫: requests, Beautiful Soup, 正则
-
python爬虫--03 Beautiful Soup库
-
Python3爬虫(六) 解析库的使用之Beautiful Soup
-
Python爬虫之Beautiful Soup库的基本使用