什么是爬虫?
通过编写程序,模拟浏览器(原始天然的爬虫工具)上网,然后让其去互联网上抓取数据(页面或部分数据)的过程
爬虫的价值:抓取数据、将数据产生价值、就业爬虫工程师
浏览器工具:
elements:是shell脚本执行后的html代码
network:网络请求抓包,记录浏览器发送给服务器的所有网络请求
source:网站中的图片资源、脚本等
requests模块
功能强大、操作简单、效率极高
作用:模拟浏览器发请求
爬取步骤(编码流程):
—指定url网址
—get(url)或者post(url)发起请求,返回响应对象:服务器返回页面源代码或者数据,浏览器执行显示页面
—text获取响源代码、json获取json数据
—with open持久化存储
#获取百度页面的源代码
import requests
url="http://www.baidu.com/"
response=requests.get(url)#返回响应对象
response.encoding="UTF-8"
print(response.text)
with open("mybaidu.html",mode='w',encoding="UTF-8") as f:
f.write(response.text)
get请求
#输入翻译内容获取翻译数据
import requests
url="https://fanyi.baidu.com/sug"
data={
"kw":input("请输入您要翻译的内容:")
}
response=requests.post(url,data=data)
print(response.json())
post请求
如果返回的是json,可以直接拿到json数据
#输入关键字获取附近肯德基餐厅的信息
import requests
url="https://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword"
data={
"cname" : "",
"pid": "",
"keyword": input("请输入餐厅关键字:"),
"pageIndex": "1",
"pageSize": "10"
}
response=requests.post(url,data=data)
print(response.json())
正则表达式
作用:匹配字符串的一门表达式语言
测试方式:在线正则表达式测试
正则支持普通字符(26个字母、文字)
元字符
用一个符号来匹配对应类型数据
\d:匹配一个数字(0-9)
\w:匹配数字、字母、下划线(0-9,a-z,A-Z,__)
\D:相对于\d取反(匹配除了数字以外的)
\W:相对于\w取反
[内容]:字符组、匹配指定内容
[^内容]:字符组匹、配除了指定内容以外的
. 匹配除了换行符以外的所有内容
量词
控制元字符出现的频次
+:前面的元字符出现一次或多次
*:前面的字符出现0次或多次(贪婪机制:尽可能多匹配结果)
?:前面的字符出现0次或一次
惰性匹配
.*?:匹配到距离xxx最近的xxx的内容
.*:匹配到距离xxx最远的xxx的内容
匹配文本:玩儿吃鸡游戏,晚上一起上游戏,干嘛呢?打游戏啊 正则表达式:玩儿.*游戏 匹配结果:玩儿吃鸡游戏,晚上一起上游戏,干嘛呢?打游戏(最远,尽可能多匹配) 正则表达式:玩儿.*?游戏 匹配结果:玩儿吃鸡游戏(最近,尽可能少匹配)
内置模re
import re
result=re.findall(r"\d+","今天我有100块,买了2个蛋糕")#返回一个匹配结果列表
result=re.search(r"\d+","今天我有100块,买了2个蛋糕")#返回一个匹配对象,存储第一次匹配的内容
print(result.group())#输出匹配的内容
result=re.finditer(r"\d+","今天我有100块,买了2个蛋糕")#返回一个匹配对象迭代器
for item in result:
print(item.group())#从match对象中拿到数据,需要group()
re.findall()
re.search()
re.finditer()
预加载
让正则和数据分开,使代码结构清晰
import re
obj=re.compile(r"\d+")#提前加载好一个正则
obj.findall("字符串")
obj.search("字符串")
obj.finditer("字符串")
import re
s="""
<div class="abc">
<div><a href="baidu.com">我是百度</a></div>
<div><a href="qq.com">我是腾讯</a></div>
<div><a href="163.com">我是网易</a></div>
</div>
"""
#compile预加载、(?P<>)起别名
obj=re.compile(r'<div><a href="(?P<url>.*?)>(?P<txt>.*?)</a></div>')
result=obj.finditer(s)
for item in result:
url=item.group("url")
txt=item.group("txt")
print(url,txt)
print(item.groupdict())#返回别名:匹配文本的字典
re.compile()
(?P<name>.*?)起别名
爬虫大案例:
#抓取的信息在网页源代码里
#目标:豆瓣top250电影信息(名称、发布日期、地区、类型、评分、评价人数),并存储至csv文件
#思路:1.拿到页面源代码2.使用re提取数据3.存储到csv文件中
import requests
import re
import pandas
movie_names = []
movie_scores = []
movie_location= []#统计
movie_type= []#统计
movie_years= []#统计
movie_nums= []
for i in range(1,11):
page=(i-1)*25
url=f"https://movie.douban.com/top250?start={page}&filter="
#因此应修改为浏览器的请求头
header={
#UA伪装,服务器对当前的网络设备进行检测
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}
response=requests.get(url,headers=header)
response.encoding="utf-8"
#处理反爬
#print(response.request.headers)#python程序的请求头默认为{'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
obj=re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>.*?<br>'
r'(?P<year>.*?) / (?P<nation>.*?) / (?P<type>.*?)'
r'</p>.*?<span class="rating_num" property="v:average">'
r'(?P<score>.*?)</span>.*?<span>(?P<num>.*?)人评价',re.S)
result = obj.findall(response.text)
for item in result:
movie_names.append(item[0])
year = item[1].strip()
movie_years.append(year)
movie_location.append(item[2])
type=item[3].strip()
movie_type.append(type)
movie_scores.append(item[4])
movie_nums.append(item[5])
# print("电影名:", movie_names)
# print("发布年限:", movie_years)
# print("地区:", movie_location)
# print("类型:", movie_type)
# print("评分列表:", movie_scores)
# print("评价人数:", movie_nums)
data = {
"电影名称": movie_names,
"发布年限": movie_years,
"地区":movie_location,
"类型":movie_type,
"评分": movie_scores,
"评分人数": movie_nums
}
df = pandas.DataFrame(data)
# 将DataFrame保存为CSV文件
df.to_csv("电影信息.csv",index=False)
.*?:过滤信息
(?P<cotent>.*?):提取目标信息