目录
Python爬虫
爬虫前基础了解
本质:模拟浏览器打开网页、获取网页中我们想要的那部分数据
**准备工作:**通过浏览器分析目标网页
获取数据:
通过http库向目标站点发起请求,请求可以包含额外的leader等信息,如果服务器能正常响应,会得到一个Response,便是所要获取的页面内容
解析内容:
得到的内容可能是html、json等格式,可以用页面解析库、正则表达式等进行解析
保存数据:
保存形式多样。可以存为文本、也可以保存到数据库、或者保存特定格式的文件
编码规范
一般Python程序的第一行需要加入
#--coding:utf-8 --或者 # coding=utf-8
这样可以在代码中包含中文
python文件可以加入main函数用于测试程序
if__name__ == “main”:
这个程序会从冒号后面开始,使程序按照自己组织的顺序来
- import bs4 #网页解析、获取数据
- import re #正则表达式、进行文字匹配
- import urllib.request,urllib.error #制定url,获取网页数据
- import xlwt #进行excel操作
- import sqlite3 #进行sqlite数据库操作
文件位置表示方法
“./”: 表示当前文件夹的位置
“.\”:表示文件系统里的位置(为了转义加了\)
r"":不用转义,直接复制电脑里面的地址
获取数据
python一般使用urllib库获取页面
获取一个get请求
复制在文本文档里打开就是百度网页
获取一个post请求(一般用在模拟用户登录)
http://httpbin.org 测试网址
超时处理
在访问网页超时时,采取行动结束访问,先去做别的事情。这里可以配合异常处理使用。
timeout 限时在多长时间内未响应便执行except里面捕获到超时错误里的内容。
要模拟一个从网页上去登录的样子,我们可以选择一个浏览器打开,点击F12,选择Network,刷新网页,点击暂停,在第一条线那里获取我们的User-Agent.
模拟从谷歌浏览器的百度网页访问豆瓣
BeautifulSoup4
将复杂HTML文档转换成一个复杂的树型结构,每个节点都是Python对象,所有对象可以归纳为4种:Tag、NavigableString、BeautifulSoup、Comment
Tag
标签及其内容:拿到它所找到的第一个内容
NavigableString
获得标签里面的内容,不包括标签头部和尾部
print(bs.title.string)
print(bs.a.atters) #将a标签里面的所有属性以字典的方式打印出来、有利于之后很好的取出想要的数据
BeautifulSoup
表示整个文档,即bs
Comment
是一个特殊的NavigableString,输出的内容不包含注释符号
文档的遍历
from bs4 import BeautifulSoup
file = open("./baidu.html", "rb") # rb:readbyte
html = file.read().decode('utf-8')
bs = BeautifulSoup(html, "html.parser")
print(bs.title)
print(bs.title.string)
print(bs.a) # 找到的第一个出现的这种标签里的所有内容
print(bs.a.attr)
print(type(bs.head))
print(type(bs.a.attrs))
# Tag的.content属性可以将tag的子节点以列表的方式输出
print(bs.head.contents)
# 用列表的索引来获取它的某一个元素
print(bs.head.contents[1])children:获取Tag的所有子节点,返回一个生成器
for child in bs.body.children:
print(child)
文档的搜索
from bs4 import BeautifulSoup
file = open("./baidu.html", "rb") # rb:readbyte
html = file.read().decode('utf-8')
bs = BeautifulSoup(html, "html.parser")
# 字符串过滤:会查找与字符串完全匹配的内容
import re
t_list = bs.find_all("a")
# print(t_list)
# 正则表达式搜索:使用search()方法来匹配内容
t_list = bs.find_all(re.compile("a")) # 只要标签里含有a就会全部输出,比如<head>
# print(t_list)
# 方法:传入一个函数(方法),根据函数的要求来搜索
def name_is_exists(tag): # 传一个标签,返回这里面的属性值
return tag.has_attr('name') # 判断对象是否包含对应的属性
t_list = bs.find_all(name_is_exists) # bs就是传入函数name_is_exists()里的参数
# kwargs 参数
t_list = bs.find_all(id="head")
t_list = bs.find_all(class_=True) # class是关键字,不能直接使用
# for item in t_list:
# print(item)
# text参数
t_list = bs.find_all(text="hao123")
t_list = bs.find_all(text=["hao123", "地图", "贴吧"])
t_list = bs.find_all(text=re.compile("\d")) # 应用正则表达式来查找包含特定文本发内容(标签里字符串) \d表示数字
# for item in t_list:
# print(item)
# limit 参数 获取多少条该标签的内容
t_list = bs.find_all("a", limit=3)
# for item in t_list:
# print(item)
# css选择器
t_list = bs.select('title') # 通过标签来查找
t_list = bs.select('.mnav') # 通过类名来查找(加点的是类名class的内容)
t_list = bs.select('#u1') # 通过id来查找(加#的是id的内容)
t_list = bs.select('a[class="bri"]') # 通过属性来查找
t_list = bs.select("head > meta>link") # 通过子标签来查找
t_list = bs.select(".mnav ~ .bri") # 通过兄弟标签来查找 ~符号表示兄弟标签
print(t_list[0].get_text()) #拿到第一个元素的文本
for item in t_list:
print(item)
正则表达式 re
判断字符串是否符合一定标准
# 正则表达式:字符串模式 (判断字符串是否符合一定的标准)
import re
# 1、创建模式对象
pat = re.compile('AA') # 这里的AA,是正则表达式,用来验证其他的字符串
# search方法:进行比对查找
m = pat.search('CBA') # search字符串被校验的内容
m = pat.search('ABCAA') # 只会检测到第一个匹配的字符
print(m)
# 没有模式对象
m = re.search("asd", "Aasd") # 前面的字符串是规则,后面的字符串是被校验的对象
print(m)
print(re.findall("a", "ADSADADDa")) # 前面的字符串是规则(正则表达式),后面的字符串是被校验的对象
print(re.findall("[A-Z]", "ADSADADDa"))
print(re.findall("[A-Z]+", "ADSaDADDa"))
# sub() 替换
print(re.sub("a", "A", "abcdcasd")) # 找到a用A替换
# 建议在正则表达式中,被比较的字符串前面加上r,不用担心转义字符的问题
a = r"\aabd-\'"
print(a)
正则表达式的常用操作符
?问号还有一个一样:表示非贪婪模式 即 只查找匹配模式的第一个字符串
如正则表达式 \S+c 匹配字符串aaaacaaaaaaac的结果是aaaacaaaaaaac,而\S+?c则会优先匹配aaaac
\s代表正则表达式中的一个空白字符(可能是空格、制表符、其他空白)
re库的主要功能函数
保存数据
excel表存储
利用python库xlwt将抽取的数据datalists写入excel表格.
完整代码
爬虫豆瓣Top250
# coding = utf-8
from bs4 import BeautifulSoup
import re
import urllib.request, urllib.error
import xlwt
import sqlite3
def main():
baseurl = "https://movie.douban.com/top250?start="
# 获取数据
datalist = getData(baseurl)
savepath = "豆瓣电影Top250.xls"
# 保存数据
saveData(datalist, savepath)
# askURL('https://movie.douban.com/top250?start=')
# 创建正则表达式对象,表示规则 ?问好表示非贪婪模式 即只会找到符合模式的第一个字符串
findLink = re.compile(r'<a href="(.*?)">') # 33行
# 影片图片的链接
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)
# 爬取网页
def getData(baseurl):
datalist = []
for i in range(0, 10): # 调用获取页面信息的函数10次
url = baseurl + str(i * 25)
html = askURL(url) # 保存获取到的网页源码
# 逐一解析数据
soup = BeautifulSoup(html, "html.parser")
for item in soup.find_all('div', class_="item"): # 查找符合要求的字符串,形成列表
# print(item)
data = []
# 保存电影信息
item = str(item)
# 获取影片详情的链接
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:
ctitle = titles[0] # 添加中文名
data.append(ctitle)
otitle = titles[1].replace("/", "") # 去掉多余的/符号
data.append(otitle) # 添加外文名
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:
inq = inq[0].replace("。", "") # 去掉句号
data.append(inq)
else:
data.append(" ") # 留空
bd = re.findall(findBd, item)[0]
bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd) # 去掉<br/>
bd = re.sub('/', " ", bd) # 替换/
data.append(bd.strip()) # 去掉前后的空格
datalist.append(data) # 把处理好的一部电影信息放入datalist
# print(datalist)
return datalist
# 得到指定一个URL的网页内容
def askURL(url):
head = { # 模拟浏览器头部信息,向豆瓣服务器发送消息
"User-Agent": "Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit /"
" 537.36(KHTML, likeGecko) Chrome / 88.0.4324.190 Safari / 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
# 保存数据
def saveData(datalist, savepath):
book = xlwt.Workbook(encoding='utf-8') # 创建workbook对象
sheet = book.add_sheet('豆瓣电影TOP250', cell_overwrite_ok=True) # 创建工作表 参数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))
data = datalist[i]
for j in range(0, 8):
sheet.write(i+1, j, data[j]) # 数据
book.save(savepath) # 保存数据表
if __name__ == "__main__":
main()
print("爬取完毕!")
爬虫微博weibo
# coding = utf-8
from bs4 import BeautifulSoup
import re
import urllib.request, urllib.error
import xlwt
import time
import sqlite3
def main():
baseurl = "https://d.weibo.com/102803_ctg1_4288_-_ctg1_4288?from=faxian_hot&mod=fenlei#"
# 获取数据
m, datalist = getData(baseurl)
savepath = "weibo.xls"
# 保存数据
saveData(datalist, savepath, m)
# askURL('https://movie.douban.com/top250?start=')
# 影片图片的链接
findtxt = re.compile(r'>.*?<', re.S)
# 爬取网页
def getData(baseurl):
datalist = []
datalist2 = []
num = 0
num2 = 0
for i in range(0, 10): # 调用获取页面信息的函数100次
url = baseurl + str(i)
html = askURL(url) # 保存获取到的网页源码
# 逐一解析数据
soup = BeautifulSoup(html, "html.parser")
for item in soup.find_all('div', class_="WB_text W_f14"): # 查找符合要求的字符串,形成列表
# print(item["nick-name"])
data = []
# # 保存电影信息
item = str(item)
txt = re.findall(findtxt, item)
for i in txt:
if ">\'][\'<" in i:
continue
if ">:<" in i:
continue
if ">回复<" in i:
continue
if "><" in i:
continue
if ">\', \'<" in i:
continue
# if "@" in i:
# continue
if "> <" in i:
continue
# if "展开全文c" in i:
# continue
# if "c" in i:
# continue
else:
data.append(i)
subTextHead = re.compile(">")
subTextFoot = re.compile("<")
m = []
for lastResult in data:
resultExcel1 = re.sub(subTextHead, '', lastResult)
resultExcel = re.sub(subTextFoot, '', resultExcel1)
# print(i, resultExcel)
m.append(resultExcel)
n = "".join(m)
num += 1
datalist.append(n)
# print(datalist,'\n')
return num, datalist
# 得到指定一个URL的网页内容
def askURL(url):
head = { # 模拟浏览器头部信息,向豆瓣服务器发送消息
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36",
"Cookie": "_T_WM=195ffb1e4f4d79574bf5fd53075f159c; SUB=_2A25NTp6DDeRhGeBM7FcY-SzKzT2IHXVusCLLrDV6PUJbkdANLUzRkW1NRNFu5Zfj1XVQl-wrxUaYGvuVn_L1hviX; SCF=AkZHVDGhzSxxLcw5odEDchdZ5rOAyiDY5Jkyp8sFGOi97Tc-EZi0tb71Jhp1zEbJs3GixyPGzd1olsFPt2t3Qb4.; SSOLoginState=1615523539"}
request = urllib.request.Request(url, headers=head)
html = ""
try:
response = urllib.request.urlopen(request)
html = response.read().decode("utf-8", "ignore")
# print(html)
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code) # 打印错误的码
if hasattr(e, "reason"):
print(e.reason) # 打印错误的原因
return html
# 保存数据
def saveData(datalist, savepath, m):
book = xlwt.Workbook(encoding='utf-8') # 创建workbook对象
sheet1 = book.add_sheet('带标签', cell_overwrite_ok=True) # 创建工作表 参数cell_overwrite_ok=True, 可以覆盖原单元格中数据
sheet2 = book.add_sheet('不带标签', cell_overwrite_ok=True) # 创建工作表 参数cell_overwrite_ok=True, 可以覆盖原单元格中数据
col = ('序号', "微博内容")
for i in range(0, 2):
sheet1.write(0, i, col[i]) # 写入列名
for i in range(0, m):
print("第%d条" % (i + 1))
data1 = datalist[i]
# print(data1)
for j in range(0, 2):
sheet1.write(i + 1, 0, i + 1)
sheet1.write(i + 1, j, data1) # 数据
book.save(savepath) # 保存数据表
if __name__ == "__main__":
star = time.time()
main()
end = time.time()
print('running time: %s Seconds' % (end - star))
print("爬取完毕!")