爬虫初识
什么是爬虫?
- 网络爬虫,是一种按照一定规则,自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性,根据用户需求定向抓取相关网页并分析已成为如今主流的爬取策略。
- 只要能通过浏览器访问的数据都可以通过爬虫抓取。
- 爬虫的本质:模拟浏览器打开网页,获取网页中我们想要的那部分数据。
1. 获取数据
python一般使用urllib2获取页面数据
import urllib.request
# 获取一个get请求
response = urllib.request.urlopen("https://www.baidu.com/")
print(response.read().decode("utf-8") # 获取到的网页资源进行utf-8解码
# 获取一个post请求
import urllib.parse
data = bytes(urllib.parse.urlencode({"hello":"world"},encoding = "utf-8"))
response = urllib.request.urlopen("http://httpbin.org/post",data = data)
print(response.read())
# 超时处理
try:
response = urllib.request.urlopen("http://httpbin.org/get",timeout=0.01)
print(response.read().decode("utf-8"))
except urllib.error.URLError as e:
print("time out!")
# 获取请求状态
response = urllib.request.urlopen("https://www.baidu.com/")
print(response.status())
# 将代理更改为模拟浏览器访问
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"
# 模拟浏览器头部信息
}
request = urllib.request.Request(url, headers=head)
2. 解析数据
通过导入from bs4 import BeautifulSoup
from bs4 import BeautifulSoup
# 打开html文件(可以自定义,但一般都是抓取的页面信息进行解析)
file = open("./文件名.html")
html = file.read()
# 通过html.parser 解析器解析网页数据,给到bs对象
bs = BeautifulSoup(html,"html.parser")
# bs对象存储网页标签元素及其内容(之能拿到找到的第一个内容),以下打印的是title标签中包含的内容 1.Tag 标签及其内容
print(bs.title)
# .string帮助拿到标签中的内容 2.通过type(bs.title.string),得到类型为NavigableString
print(bs.title.string)
# .attrs拿到该标签下的所有属性,并以键值对(字典)的方式表示
print(bs.a.attrs)
# 3.BeautifulSoup类型,拿到网页所有元素
print(bs)
# 4.Comment 是一个特殊的NavigableString 输出内容不包含注释符号
2.1 遍历文档树
- .contents :获取Tag的所有子节点,返回一个list
# tag的.content 属性可以将tag的子节点以列表的方式输出
print(bs.head.content)
# 用列表索引来获取它的某一个元素
print(bs.head.content[1])
- children : 获取tag所有子节点返回一个生成器
for child in bs.body.children:
print(child)
2.2文档搜索
# 1.find_all()
# 通过find_all()方法找到所有的a标签:字符串过滤,会查找到与字符串完全匹配的内容
t_list = bs.find_all(a)
print(t_list)
# 正则表达式搜索,使用search()方法来匹配内容
t_list = bs.find_all(re.compile("a")) # 查询到列表标签包含a字符串的内容
print(t_list)
# 方法:传入一个函数(方法),根据函数的要求来搜索
def name_is_exists(tag):
return tag.has_attr("name") #找到元素包含name属性的标签
t_list = bs.find_all(name_is_exists)
print(t_list)
# 2. Kwargs 参数:指定参数进行搜索
t_list = bs.find_all(id="head") # 查询属性id 等于head 的内容
t_list = bs.find_all(class_=True) # 打印标签包含class属性的内容
# 3. text 参数
t_list= bs.find_all(text="hao123") #打印结果为 hao123
t_list= bs.find_all(text= re.compile("/d")) # 通过正则表达式打印出所有文本内容带数字的内容
# 4.limit 参数 控制输出的个数
t_list= bs.find_all("a",limit=3) # 找到html中前三个带a标签的内容
# 5.css选择器
t_list= bs.select('title') # 通过标签来查找
t_list= bs.select('.类名') # 通过类名
t_list= bs.select('id') # 通过id
t_list= bs.select("a[class = 名字]") # 查找a标签中 class= 名字 的内容
t_list= bs.select("head > title") # 找到父标签head下的子标签 title
t_list= bs.select(".类名1 ~ .类名2") # 找到.类名1 的兄弟标签.类名2
# 打印兄弟标签的内容
print(t_list[0].get_test())
# 通过for循环打印出来的内容更易阅读
for item in t_list:
print(t_list)
2.3 正则表达式
通用,且常用的正则表达式
操作符 | 说明 | 实例 |
---|---|---|
. | 表示任何单个字符 | |
[ ] | 字符集,对单个字符给出取值范围 | [abc] 表示a、b、c,[a-z]表示a到z单个字符 |
[^ ] | 非字符集,对单个字符u给出排除范围 | [^abc] 非a或b或c的单个字符 |
* | 前一个字符0次或无限次扩展 | abc* 表示 ab、abc、abcc、abccc等 |
+ | 前一个字符1次或无限次扩展 | abc+ 表示abc、abcc、abccc等 |
? | 前一个字符0次或1次扩展 | abc? 表示ab、abc |
丨 | 左右表达式任意一个 | abd丨def 表示abc、def |
“左闭右开”是指区间不包括左边的内容,但是涵盖右边的内容。 | ||
操作符 | 说明 | 实例 |
– | – | – |
{m} | 扩展前一个字符m次 | ab{2}c 表示abbc,ab{3}c 表示abbbc |
{m,n} | 扩展前一个字符m至n次(含n) | ab{1,2} c 表示abc、abbc |
^ | 匹配字符串开头 | ^abc 表示abc且在一个字符串的开头 |
$ | 匹配字符串结尾 | abc$ 表示abc且在一个字符串的结尾 |
( ) | 分组标记,内部只能使用丨操作符 | (abc)表示abc,(abc丨def)表示abc、def |
\d | 数字,等价于[0-9] | |
\w | 单词字符,等价于[A-Za-z0-9] | 表示A到Z,a到z,数字0到9 |
Import re
导入的re库的主要功能函数
函数 | 说明 |
---|---|
re.search() | 在字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对像 |
re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
re.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的字串,返回替换后的字符串 |
3. 数据存储
3.1 数据存储–excel
import xlwt
# 创建workbook 对象
workbook = xlwt.Workbook(encoding="utf-8")
# 创建工作表
worksheet = workbook.add_sheet('sheet1')
# 例: 存入九九乘法表
for i in range(1, 10):
for j in range(1, i+1):
worksheet.write(i-1, j-1, "%d * %d = %d" % (i, j, i*j))
# 保存数据表
workbook.save('student.xls')
3.2 数据存储–SQLite
(后期补上)
4. 交流学习
5. 爬取源码
from bs4 import BeautifulSoup # 网页解析,获取数据
import re # 正则表达式,进行文字匹配
import urllib.request, urllib.error # 指定URL, 获取网页数据
import xlwt # 进行excel操作
import sqlite3 # 进行SQLite进行数据库的操作
def main():
# 获取网页链接
base_url = "https://movie.***(某电影网站).com/top250?start="
# 1.爬取网页
datalist = getData(base_url)
savePath = "某电影电影top250.xls"
# 3.保存数据
saveData(savePath, datalist)
# 创建正则表达式对象,表示规则(字符串模式)
# 影片详情链接规则
findLink = re.compile(r'<a href="(.*?)">')
# 影片图片
findImgSrc = re.compile(r'<img.*src="(.*?)"/>', re.S) # re.S 让换行符包含在字符中
# 影片片名
findTitle = re.compile(r'<span class="title">(.*)</span>')
# 影片评分
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
# 评价人数
findJudge = re.compile(r'<span>(\d*)人评价</span>')
# 概况
findInq = re.compile(r'<span class="inq">(.*)</span>')
# 找到影片的相关内容
findBd = re.compile(r'<p class="">(.*?)</p>', re.S)
# 1.爬取网页
def getData(base_url):
datalist = []
for i in range(0, 10): # 调用获取页面信息的函数10次
url = base_url + str(i * 25) # 为参数start赋值
html = askURL(url) # 获取到的一页html,返回给到html对象
# 2.逐一解析数据(在爬取页面时就直接解析,而不是爬取所有在解析)
# 解析器:html.parser 解析html
soup = BeautifulSoup(html, "html.parser")
# 查找网页所有的内容,取标签为div 属性为item的div
for item in soup.find_all("div", class_="item"):
data = [] # 保存一部电影的所有信息
item = str(item) # 转成字符串
# 比较规则为findLink 从item里面找出符合findlink规则的内容取第一个符合条件的
link = re.findall(findLink, item)[0] # 获取影片链接
data.append(link) # 将链接添加到数组中
# 添加图片
imgSrc = re.findall(findImgSrc, item)[0]
data.append(imgSrc)
# 片名存在中文名,或者中文加外文名
titles = re.findall(findTitle, item)
if len(titles) == 2:
# 添加中文名
chinese_title = titles[0]
data.append(chinese_title)
# 添加外文名 .replace("/", "") 将字符/ 用空值代替
foreign_title = titles[1].replace("/", "")
data.append(foreign_title)
else:
data.append(titles[0])
data.append(' ') # 没有外国名字时 外国名字留空
# 评分
rating = re.findall(findRating, item)[0]
data.append(rating)
# 评价人数
judgeNum = re.findall(findJudge, item)[0]
data.append(judgeNum)
# 概况
inq = re.findall(findInq, item)
if len(inq) != 0:
inq1 = inq[0].replace("。", "")
data.append(inq1)
else:
data.append(' ')
# 电影相关内容
bd = re.findall(findBd, item)[0]
# 将bd 对象中的<br>标签
bd = re.sub(r'<br(\s+)?/>(\s+)?', "", bd)
# 替换\
bd = re.sub('/', " ", bd)
# 去掉前后空格
data.append(bd.strip())
datalist.append(data)
print(datalist)
return datalist
# 3.保存数据
def saveData(savePath, datalist):
# 创建workbook 对象
book = xlwt.Workbook(encoding="utf-8", style_compression=0)
# 创建工作表
sheet = book.add_sheet('某电影Top250', cell_overwrite_ok=True)
col = ("电影链接", "图片链接", "影片中文名", "影片外文名", "评分", "评价数", "概况", "相关信息")
for i in range(0, 8):
sheet.write(0, i, col[i]) # 写入列名
for i in range(0, 250):
print("第%d条" % (i+1))
# 取datalist中的第i条数据存入data对象
data = datalist[i]
for j in range(0, 8):
# 将data中的第一条数据 存成8列
sheet.write(i+1, j, data[j])
# 保存数据表
book.save(savePath)
# 得到一个指定URL的网页内容(一共250 条,需要爬取25个页面)
def askURL(url):
# User - Agent 告诉豆瓣服务器,我们是什么类型的机器
head = {
"User-Agent": "Mozilla/ 5.0(Windows NT 10.0;Win64; x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 96.0.4664.93Safari / 537.36"
# 模拟浏览器头部信息
}
request = urllib.request.Request(url, headers=head)
html = ""
try:
response = urllib.request.urlopen(request)
html = response.read().decode("utf-8")
# print(html)
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
return html
if __name__ == '__main__':
main()
print("爬取完毕")