文章目录
前言
来张爬取的镇楼
大创需要用到爬虫,当时学python没有系统学过,在这里自己自学一下,做个笔记方便日后复习,若有不对,还请斧正"🐂"
入门
通过urliib.request.urlopen()函数访问页面
安装库
在命令提示符输入pip+list可以看自己安装了哪些库
需要安装以下库:
- request:通过http请求获取页面
- lxml:支持html和xml的解析,支持xpath解析,效率高
- Beautiful Soup4:可以从html或xml中提取数据
没有的在终端输入以下命令
python -m pip install beautifulsoup4
python -m pip install lxml
python -m pip install requests
什么是编码
html.decode(“utf-8”)可以解码变成Unicode编码,再从encode()编码成另一种编码
实战
- urlopen里面有:
- geturl()返回请求的url
- info()返回一个httplib.HTTPMessage对象
- getcode()返回HTTP状态码
- read()读取内容
- GET是从服务器请求数据
POST是向服务器提交被处理的数据- urlopen()中的data参数,该参数赋值的话,HTTP请求就是用POST方式,若是NULL默认值,HTTP请求就是GET方式
- json.loads()用来解析JSON格式的字符串【变成一个字典】
隐藏
修改User-Agent
- 实例化request对象的时候将headers参数传进去
- add_header()往request对象添加headers
延迟提交数据
用time模块,但效率低
eg:time.sleep()
使用代理
- proxy_support=urllib.request.ProxyHandler({})
- opener=urllib.request.build_ioener(proxy_support)
- build_opener()可以创建私人定制的opener
- urllib.request.install_opener(opener)
- 将定制好的opener安装到系统上
- 不想换掉默认,可以用opener.open()的方式打开网页
Beautiful Soup
BeautifulSoup(html,“html.parser”)有两个参数,前者是需要提取的HTML或者XML文件,后者是指定解析器
正则表达式
“当你发现一个问题可以用正则表达式来解决的时候,于是你就有了两个问题——王涛” 🐂🐎
re模块
search()方法用于在字符串中搜索正则表达式第一次出现的位置,找不到返回None
通配符
可以用(,)表示,可以匹配除了换行符之外的任何字符
反斜杠
反斜杠可以剥夺元字符的特殊能力,还能使普通字符拥有特殊能力
字符类
- 表示一个字符的范围,用中括号打包起来;字符类中的任何一个字符匹配,就算匹配成功
- [ ]里面可以用“-”表示范围
重复匹配
- 用{}对元字符实现重复匹配功能
- 重复的次数也可以取一个范围;eg{3,5}
特殊符号及用法
特殊符号有:元字符和“\”+普通字符
元字符
- .表示匹配除换行符之外的任何字符
- |表示逻辑或操作
- ^表示匹配字符串的开始位置
- $表示匹配字符串的结束位置
- \可以剥夺元字符的特殊能力,还能使普通字符拥有特殊能力
- “\” +(1~99)的数字表示引用序号对应的子组所匹配的字符串
- “\” +三位数字,表示这个八进制数对应的ASCII字符
- [ ]表示生成一个字符类,包围在里面的元字符都失去了特殊功能【除了几个特殊字符:-(表示范围) \(表示转义) ^(表示取反)】
- { }表示做重复事情【表示重复的元字符还有(*){0,}, (+){1,},(?)=={0,1}】
正则表达式不要随便加空格
贪婪与非贪婪
正则表达式默认启用贪婪匹配模式
启用非贪婪模式:重复元素后面加(?)
反斜杠+普通字母=特殊含义
- “\” +(1~99)的数字表示引用序号对应的子组所匹配的字符串
- “\” +三位数字,表示这个八进制数对应的ASCII字符
- (\A)==(^)
- (\Z)==($)
- \b表示匹配一个单词的边界
- \B表示匹配一个非单词的边界
- \d表示匹配的是Unicode中定义的数字字符
- \D表示匹配的是非Unicode中定义的数字字符
……
编译正则表达式
重复使用某个正则表达式,用 re.compile() 方法编译成模式对象
编译标志
通过编译标志,可以修改正则表达式的工作方式
实用的方法
- re.search() 不会立刻返回你可以使用的字符串,取而代之的是一个匹配对象,这时候用 group() 才可以获得匹配的字符串
- start() 返回匹配的开始位置;end() 返回匹配的结束位置;span() 返回匹配的范围
- findall() 找到所有匹配的内容,组织成列表返回
- finditer() 会将结果返回一个迭代器,方便以迭代的方式获取
- sub() 实现字符串的替换
异常处理
URLError
HTTPError
404 页面无法找到
403 请求终止
401 验证请求
处理异常
实例
os模块
方法 | 解释 |
---|---|
os.getcwd() | 查看当前工作工作目录 |
os.listdir() | 查看某个目录下的文件列表 |
os.chdir(‘fileUrl’) | 修改工作目录 |
os.mkdir(’ ’) | 创建单层目录 |
os.makedirs(‘fileurl’) | 创建多级文件目录 |
os.remove(’’) | 删除文件 |
os.rmdir(’’) | 删除单层文件目录 |
os.removedirs(’’) | 递归尝试删除多级空文件目录 |
os.rename(’’) | 更名文件目录 |
os.system(’’) | 模拟shell命令 |
os.pardir | 指代上一级文件目录 |
os.curdir | 指代当前目录 |
requests模块
方法 | 解释 |
---|---|
requests.request() | 构造一个请求,支持以下各种方法 |
requests.get() | 获取html的主要方法 |
requests.head() | 获取html头部信息的主要方法 |
requests.post() | 向html网页提交post请求的方法 |
requests.put() | 向html网页提交put请求的方法 |
requests.patch() | 向html提交局部修改的请求 |
requests.delete() | 向html提交删除请求 |
re模块
用途
- 测试字符串内的模式。
- 替换文本
- 基于模式匹配从字符串中提取子字符串。
语法
'.' 匹配所有字符串,除\n以外
'-' 表示范围[0-9]
'*' 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
'+' 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+
'^' 匹配字符串开头
'$' 匹配字符串结尾 re
'\' 转义字符, 使后一个字符改变原来的意思,如果字符串中有字符*需要匹配,可以\*或者字符集[*] re.findall(r'3\*','3*ds')结['3*']
'*' 匹配前面的字符0次或多次 re.findall("ab*","cabc3abcbbac")结果:['ab', 'ab', 'a']
'?' 匹配前一个字符串0次或1次 re.findall('ab?','abcabcabcadf')结果['ab', 'ab', 'ab', 'a']
'{m}' 匹配前一个字符m次 re.findall('cb{1}','bchbchcbfbcbb')结果['cb', 'cb']
'{n,m}' 匹配前一个字符n到m次 re.findall('cb{2,3}','bchbchcbfbcbb')结果['cbb']
'\d' 匹配数字,等于[0-9] re.findall('\d','电话:10086')结果['1', '0', '0', '8', '6']
'\D' 匹配非数字,等于[^0-9] re.findall('\D','电话:10086')结果['电', '话', ':']
'\w' 匹配字母和数字,等于[A-Za-z0-9] re.findall('\w','alex123,./;;;')结果['a', 'l', 'e', 'x', '1', '2', '3']
'\W' 匹配非英文字母和数字,等于[^A-Za-z0-9] re.findall('\W','alex123,./;;;')结果[',', '.', '/', ';', ';', ';']
'\s' 匹配空白字符 re.findall('\s','3*ds \t\n')结果[' ', '\t', '\n']
'\S' 匹配非空白字符 re.findall('\s','3*ds \t\n')结果['3', '*', 'd', 's']
'\A' 匹配字符串开头
'\Z' 匹配字符串结尾
'\b' 匹配单词的词首和词尾,单词被定义为一个字母数字序列,因此词尾是用空白符或非字母数字符来表示的
'\B' 与\b相反,只在当前位置不在单词边界时匹配
[] 是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示相应位置的字符要匹配英文字符和数字。[\s*]表示空格或者*号
'(?P<name>...)' 分组,除了原有编号外在指定一个额外的别名
Eg: re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{8})","371481199306143242").groupdict("city")
结果{'province': '3714', 'city': '81', 'birthday': '19930614'}
方法 | 解释 |
---|---|
re.compile() | 编译正则表达式模式,返回一个对象 |
re.match() | 尝试从一个字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,则返回None |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号 |
re.search() | 扫描整个字符串并返回第一个成功的匹配 |
re.sub() | 用于替换字符串中的匹配项 |
findall() | 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表 |
re.finditer() | 在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回 |
re.split() | 按照能够匹配的子串将字符串分割后返回列表 |
BeautifulSoup模块
方法 | 解释 |
---|---|
find_all() | 根据标签,属性,内容查找文档 |
Begin~~~
爬取网址彼岸桌面
列表页规则为 http://www.netbian.com/mei/index_{页码}.htm
实现目标
- 生成所有列表页 URL 地址;
- 遍历列表页 URL 地址,并获取图片详情页地址;
- 进入详情页获取大图;
- 保存图片;
- 得到 2000 张图片之后,开始欣赏。
具体详解参见代码注释
import requests
import re
import time
# 请求函数
def request_get(url, ret_type="text", timeout=5, encoding="GBK"):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
}
res = requests.get(url=url, headers=headers, timeout=timeout)
res.encoding = encoding
if ret_type == "text":
return res.text
elif ret_type == "image":
return res.content
# 抓取函数
def main():
n = int(input('请输入爬取的页数:'))
urls = [f"http://www.netbian.com/mei/index_{i}.htm" for i in range(2, n)]
url = "http://www.netbian.com/mei/index.htm"
urls.insert(0, url)
for url in urls:
print("抓取列表页地址为:", url)
text = request_get(url)
format(text)
# 解析函数
def format(text):
origin_text = split_str(text, '<div class="list">', '<div class="page">')
pattern = re.compile('href="(.*?)"')
hrefs = pattern.findall(origin_text)
hrefs = [i for i in hrefs if i.find("desk") > 0]
for href in hrefs:
url = f"http://www.netbian.com{href}"
print(f"正在下载:{url}")
text = request_get(url)
format_detail(text)
def split_str(text, s_html, e_html):
start = text.find(s_html) + len(e_html)
end = text.find(e_html)
origin_text = text[start:end]
return origin_text
def format_detail(text):
origin_text = split_str(text, '<div class="pic">', '<div class="pic-down">')
pattern = re.compile('src="(.*?)"')
image_src = pattern.search(origin_text).group(1)
# 保存图片
save_image(image_src)
# 存储函数
def save_image(image_src):
content = request_get(image_src, "image")
with open(f"{str(time.time())}.jpg", "wb") as f:
f.write(content)
print("图片保存成功")
if __name__ == '__main__':
main()
效果如下
总结
QAQ 依旧是菜的一天