爬虫详细教程第2天
爬虫详细教程第2天
各位小伙伴想要博客相关资料的话关注公众号:chuanyeTry即可领取相关资料!
1. 解析网页
解析网页的三种解析方式:
- re解析
- bs4解析
- xpath解析
2.正则表达式
2.1概念
正则表达式, 一种使用表达式的方式对字符串进行匹配的语法规则.
正则的优点: 速度快, 效率高, 准确性高
正则的缺点: 新手上手难度有点儿高.
正则的语法: 使用元字符进行排列组合用来匹配字符串
在线测试正则表达式https://tool.oschina.net/regex/
链接: 在线测试正则表达式
元字符: 具有固定含义的特殊符号。
- 常用元字符如下:
- . 匹配除换行符以外的任意字符
- \w 匹配字母或数字或下划线
- \s 匹配任意的空白符
- \d 匹配数字
- \n 匹配一个换行符
- \t 匹配一个制表符
- ^ 匹配字符串的开始
- $ 匹配字符串的结尾
- \W 匹配非字母或数字或下划线
- \D 匹配非数字
- \S 匹配非空白符
- a|b 匹配字符a或字符b
- () 匹配括号内的表达式,也表示一个组
- […] 匹配字符组中的字符
- [^…]匹配除了字符组中字符的所有字符
量词: 控制前?的元字符出现的次数
- 1.* 重复零次或更多次
- 2.+ 重复一次或更多次
- 3.? 重复零次或一次
- 4.{n} 重复n次
- 5.{n,} 重复n次或更多次
- 6.{n,m} 重复n到m次
贪婪匹配和惰性匹配
- .* 贪婪匹配
- .*? 惰性匹配
3.re模块
- findall 查找所有. 返回list
lst = re.findall("m", "mai le fo len, mai nimei!")
print(lst) # ['m', 'm', 'm']
lst = re.findall(r"\d+", "5点之前. 你要给我 5000万")
print(lst) # ['5', '5000']
- search 会进行匹配. 但是如果匹配到了第一个结果. 就会返回这
个结果. 如果匹配不上search返回的则是None
ret = re.search(r'\d', '5点之前. 你要给我 5000万').group()
print(ret) # 5
- match 只能从字符串的开头进行匹配
ret = re.match('a', 'abc').group()
print(ret) # a
- finditer, 和findall差不多. 只不过这时返回的是迭代器(重点)
it = re.finditer("m", "mai le fo len, mai ni mei!")
for el in it:
print(el.group()) # 依然需要分组
- compile() 可以将一个正则进行预加载. 方便后面的使用
obj = re.compile(r'\d{3}') # 将正则表达式编译成为一个正则表达式对象, 规则要匹配的是3个数字
ret = obj.search('abc123eeee') # 正则表达式对象调用search, 参数为待匹配的字符串
print(ret.group()) # 结果: 123
- 正则中的内容如何单独提取?单独获取到正则中的具体内容可以给分组起名字
s = """
<div class='?游记'><span id='10010'>中国联通</span></div>
"""
obj = re.compile(r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>",re.S)
result = obj.search(s)
print(result.group()) # 结果: <spanid='10010'>中国联通</span>
print(result.group("id")) # 结果: 10010 # 获取id组的内容
print(result.group("name")) # 结果: 中国联通 #获取name组的内容
这里可以看到我们可以通过使用分组. 来对正则匹配到的内容进
一步的进行筛选.
4.豆瓣TOP250电影
目标: 抓取"电影名称",“上映年份”,“评分”,"评分人数"四项内容.怎么做呢?
首先, 先看一下页面源代码. 数据是否是在源代码上的?很明显, 我们想要的数据全部都在页面源代码中体现了. 接下来第一步了. 拿到?面源代码,然后呢. 从?面源代码中提取我们需要的内容. 这时候我们就可以去写正则了.
import requests
headers = {
"user-agent": "Mozilla/5.0 (Macintosh; IntelMac OS X 10_15_4)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
}
url = "https://movie.douban.com/top250?start=0&filter="
resp = requests.get(url, headers=headers)
print(resp.text)
obj = re.compile(r'<li>.*?<div class="item">.*?
<div class="pic">.*?<em class="">(?P<num>\d+)
</em>'
r'.*?<span class="title">(?
P<name>.*?)</span>'
r'.*?<p class="">.*?<br>\n(?
P<year>.*?) '
r'.*?property="v:average">(?
P<average>.*?)</span>'
r'.*?<span>(?P<people>\d+)?评价
</span>', re.S)
开始匹配, 将最终完整的数据按照自己喜欢(需要)的方式写入文件.
it = obj.finditer(resp.text)
with open("movie.csv", mode="w", encoding="utf-8") as f:
csvwriter = csv.writer(f) # 创建csv文件写入工具,也可以直f.write()
for item in it:
dic = item.groupdict()
dic['year'] = dic['year'].strip()
csvwriter.writerow(dic.values()) # 写入数据
5.bs4解析-HTML语法
bs4解析比较简单, 但是呢, 首先你需要了解一丢丢的html知识. 然后再去使用bs4去提取, 因为bs4就是通过html标签和属性去定位?面上的内容的。
<body text="green" bgcolor="#eee">
你看我的颜色. 贼健康
</body>
<标签 属性=“值” 属性=“值”>
被标记的内容
</标签>
6.bs4解析-bs4模块安装和使用
6.1bs4模块安装
在python中我一般只推荐用pip进行安装. 原因: 简单!!!
pip install bs4
bs4在使用的时候就需要参照一些html的基本语法来进行使用了. 我们直接上案例. 案例是最能直观的展现出bs4的便捷效果的.
6.2bs4模块使用
我们来尝试抓取链接: link
http://www.xinfadi.com.cn/marketanalysis/0/list/1.shtml
老规矩, 先获取?面源代码. 并且确定数据就在?面源代码中~
import requests
from bs4 import BeautifulSoup
resp =
requests.get("http://www.xinfadi.com.cn/market
analysis/0/list/1.shtml")
print(resp.text)
将?面源代码丢给BeautifulSoup, 然后我们就可以通过bs对象去检索?面源代码中的html标签了
page = BeautifulSoup(resp.text)
BeautifulSoup对象获取html中的内容主要通过两个方法来完成
find()
find_all()
基本上有这两个方法就够用了. 不论是find还是find_all 参数几乎是一致的.
语法:
- find(标签, 属性=值)
意思是在页面中查找 xxx标签, 并且标签的xxx属性必须是xxx值
例:find(‘div’, age=18) 含义: 在?面中查找div标签, 并且属性age必须是 18的这个标签.
find_all()的用法和find()几乎一致.
find()查找 1 个. ,find_all()查找?面中所有的.
<div class="honor">
page.find("div", class="honor")
注意, python中class是关键字. 会报错的. 怎么办呢? 可以在class后面加个下划线
page.find("div", class_="honor")
好了, 用法说完了. 接下来就回来看怎么抓取新发地的价格吧
table = page.find("table", class_="hq_table")
print(table)
接下来就可以进一步去提取数据了. 后面的直接给出完整代码.因为逻辑都是一样的. 并没有多么的复杂, 过程就省略了.
import requests
from bs4 import BeautifulSoup
import csv
resp =
requests.get("http://www.xinfadi.com.cn/marke
tanalysis/0/list/1.shtml")
page = BeautifulSoup(resp.text)
table = page.find("table", class_="hq_table")
f = open("新发地.csv", mode="w",
encoding="utf-8")
cv_writer = csv.writer(f)
# 提取到所有tr
tr_list = table.find_all("tr")[ 1 :] # 注意,第一
行并不是我想要的数据. (第一行是表头)
for tr in tr_list:
td_list = tr.find_all("td")
name = td_list[ 0 ].text # 获取文本内容
low = td_list[ 1 ].text
avg = td_list[ 2 ].text
high = td_list[ 3 ].text
gui = td_list[ 4 ].text
dan = td_list[ 5 ].text
day = td_list[ 6 ].text
cv_writer.writerow([name, low, avg, high,
gui, dan, day])
f.close()
print("搞定")
有人可能要问了. 为什么只有第一?数据. 你观察一下第二?, 第
三?的url就明白了了
http://www.xinfadi.com.cn/marketanalysis/ 0 /list/1.shtml
http://www.xinfadi.com.cn/marketanalysis/ 0 /list/2.shtml
http://www.xinfadi.com.cn/marketanalysis/ 0 /list/3.shtml
7.抓取图片
我们以优美图库作为本节课的案例。
链接:优美图库https://www.umei.cc/bizhitupian/weimeibizhi/
我需要在网站的首?中, 找到子?面的链接, 然后请求到子?面, 才能看到图片>也就是说, 想要下载该网站图片(高清大图), 需要三步,
第一步, 在主?面中拿到每一个图片的子?面链接
第二步, 在子?面中找到真正的图片下载地址
第三步, 下载图片
1.拿到子?面链接
def main_page():
with open("child_page_href.txt", mode="w") as
f:
for i in range( 1 , 56 ):
try:
resp =requests.get(f"https://www.umei.cc/bizhitupian/weimeibizhi/{i}.htm")
# <meta http-equiv="Content-Type"content="text/html; charset=utf-8" />
resp.encoding = 'utf-8' # 处理中文乱码, 这里要和?面上的charset对应
main_page =BeautifulSoup(resp.text, "html.parser")
typeListDiv =main_page.find("div", attrs={"class":"TypeList"})
main_a_list =typeListDiv.find_all("a")
for main_a in main_a_list:
href = main_a.get("href") #拿到某一个标签中xxx属性的值
f.write(href)
f.write("\n")
print(f"https://www.umei.cc/bizhitupian/weimeibizhi/{i}.htm, 成功了!")
time.sleep(0.5)
except:
print(f"https://www.umei.cc/bizhitupian/weimeibizhi/{i}.htm, 出错了")
print(resp.text)
break # 也可以记录下来, 供以后查错用
2.获取到子页面信息, 找到下载图片的图片路径
def child_page():
with open("child_page_href.txt", mode="r") as
f:
for line in f:
line = line.strip()
resp = requests.get(line)
resp.encoding='utf-8'
child = BeautifulSoup(resp.text,"html.parser")
div = child.find("div",class_="ImageBody")
img = div.find("img")
if img:
src = img.get("src")
print(src)
else:
print(line, "没有图片")
- 下载图片
def download_img(src):
with open("img/"+src.split("/")[- 1 ],mode="wb") as f:
resp = requests.get(src) # 下载图片
f.write(resp.content) # 图片写入文件
print(src, "down!")
最后运行一下, 看看结果对了一定记着把img文件夹设置为excluded, 否则你的pycharm会奇卡无比
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!