视频资源来自:b站——Python爬虫编程基础5天速成P15-P28
文章仅为个人观看视频后的学习心得笔记,用于个人查看和记录保存。文中定有疏漏错误之处,恳请指正。
Python爬虫
任务介绍
百度指数,可以看搜索量数据哈哈哈哈
爬虫知识
基本流程
准备工作
1.分析页面
Headers
2.编码规范
一般Python程序第一行需要加入
#-*-coding:utf-8 -*-
或者# coding=utf-8
。这样代码可以包含中文
Python文件中可以加入main函数用于测试程序。(程序入口)
if __name__ == "__main__" :
3.引入模块
moudule 模块,package包。包是含有Python模块的文件夹,为了防止模块名冲突,python引入的按目录组织模块的方法
from test1 import t1
从包test1里导入模块t1
Settings -> Project [myProject] ->Project Interpreter 解释器 里保存了很多 第三方包
安装:pip install bs4
也可以在解释器设置里点+
搜索安装
from bs4 import BeautifulSoup #网页解析,获取数据
import re #正则表达式,进行文字匹配
import urllib.request,urllib.error #指定URL,获取网页数据
import xlwt #进行excel操作
import sqlite3 #进行SQLite数据库操作
def main():
baseurl = 'https://movie.douban.com/top250'
#1爬取网页
datalist = getData(baseurl)
savePath = r".\豆瓣电影Top250.xls"
#3.保存数据
saveData(savePath)
获取数据
补充:head
用户代理,标识告诉豆瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉服务器,我们可以接收什么水平的文件内容)
# 爬取网页
def getData(baseurl):
datalist = []
for i in range(0, 250, 25): # 调用获取页面信息的函数,一共250条,一页25条。(所以一共10次)
url = baseurl + str(i)
html = askURL(url) # 保存获取到的网页源码
# 2逐一解析数据
return datalist
# 得到指定一个URL的网页内容
def askURL(url):
# 模拟浏览器头部信息,向豆瓣服务器发送消息
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 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
解析内容
补充:
BeautifulSoup
正则表达式
正则表达式<a href="(.*?)">
.*?
非贪婪匹配。表示重复任意次,但是尽可能的少重复。否则后面的">也会被匹配进去
link = re.findall(re.compile(r'<a href="(.*?)">'),item)[0]
这里正则表达式里加了括号。括号里的内容是最终匹配输出的 链接。如果把括号去掉,那么<a 标签 什么的都会显示出来。如果这里有2对括号,那么结果就是有2个值的列表。
findLink = re.compile(r'<a href="(.*?)">')
findImgSrc = re.compile(r'<img.*src="(.*?)"',re.S)
findTitle = re.compile(r'<span class="title">(.*?)</span>')
findScore = 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)
re.S让换行符包含在字符中
保存数据
Excel保存(xlwt)
write(行,列,内容)
写入九九乘法表数据
import xlwt
workbook = xlwt.Workbook(encoding='utf-8')#创建workbook对象
worksheet = workbook.add_sheet('sheet1')#创建工作表
#worksheet.write(0,0,'hello')#写入数据:行,列,内容
for i in range(9):
for j in range(i+1):
worksheet.write(i,j,f'{j+1}*{i+1}={(i + 1) * (j + 1)}')
workbook.save('student.xls')
实例:
def saveData(savepath,datalist):
book = xlwt.Workbook(encoding='utf-8',style_compression=0) #样式压缩
sheet = book.add_sheet('豆瓣电影Top250',cell_overwrite_ok=True) #可以覆盖单元格
col = ('电影详情链接','图片链接','影片中文名','影片外国名','评分','评价数','概况','相关信息')
# worksheet.write(0,0,'hello')#写入数据:行,列,内容
for i in range(8):
sheet.write(0,i,col[i])
for i in range(250):
print(f'正在保存第{i+1}条')
data = datalist[i]
for j in range(8):
sheet.write(i+1,j,data[j])
book.save('豆瓣电影Top250.xls')
SQL保存(sqlite3)
补充:sqlite3
初始化数据库,建表:
def init_db(dbpath):
sql = '''
create table movie250
(
id integer primary key autoincrement,
info_link text,
pic_link text,
cname varchar,
ename varchar,
score numeric,
rated numeric ,
instroduction text,
info text
)
'''
conn = sqlite3.connect(dbpath)
cursor = conn.cursor()
cursor.execute(sql)
conn.commit()
conn.close()
写入数据:
def saveDataDB(dbpath,datalist):
init_db(dbpath)
conn = sqlite3.connect(dbpath)
cur = conn.cursor()
for data in datalist:
for index in range(len(data)):
if index == 4 or index == 5:
continue
data[index] = '"'+data[index]+'"'
sql ='''
insert into movie250 (info_link,pic_link,cname,ename,score,rated,instroduction,info)
values(%s)''' % ",".join(data)
print(sql)
cur.execute(sql)
conn.commit()
cur.close()
conn.close()
补充内容
head
import urllib.request
#获取一个get请求
response=urllib.request.urlopen("http://www.baidu.com")
print(response.read().decode("utf-8")) #对获取到的网页源码进行utf-8的解码
response、response.read()、response.read().decode("utf-8")
get请求:
这里User-Agent 就告诉浏览器自己是爬虫。(不然就会给一些浏览器信息)
import urllib.request
import urllib.parse
#获取一个post请求
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read().decode("utf-8"))
超时处理:
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!')
服务器返回错误码:418。拒绝访问请求!我是一个茶壶!
啊~被发现是爬虫了
response = urllib.request.urlopen('http://www.baidu.com/')
print(response.status)
print(response.getheaders())
print(response.getheader("Server"))
随便找个网页,找到包里的user-agent。这就是我们真实的浏览器信息!!骗过服务器。要是整个包都复制下来封装好,发过去,那就是真实的浏览器请求!!
豆瓣的访问:
url = "https://www.douban.com"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
}
req = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(req)
print(response.read().decode("utf-8"))
User-Agent必须一模一样!不然就伪装失败
BeautifulSoup
BeautifulSoup4将复杂html文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
Tag、NavigableString、BeautifulSoup、Comment
BeautifulSoup(html,'html.parser')
用BeautifulSoup解析一个html(变量)的文件。使用的解析器叫html.parser
from bs4 import BeautifulSoup
file = open("./baidu.html",'rb')
html = file.read()
bs = BeautifulSoup(html,'html.parser')
print(bs.title)
print(bs.a)
Tag:拿到它所找到的第一个标签+内容
print(bs.title.string)
print(bs.a.attrs)
获取内容、获取属性
输出:
百度一下,你就知道
{'class': ['mnav'], 'href': 'http://news.baidu.com', 'name': 'tj_trnews'}
comment是一个特殊的NavigableString,输出的内容不包含注释符号
文档的遍历:
print(bs.head.contents):返回一个列表,包含了head里面的东西们
字符串过滤:会查找与字符串完全匹配的内容。
所有的a标签↓加了limit之后,就只显示前3个。
t_list = bs.find_all('a')
t_list = bs.find_all('a',limit=3)
正则表达式搜索:使用search()方法来匹配内容
所有标签里有a的↓
import re
t_list = bs.find_all(re.compile("a"))
方法:传入一个函数(方法),根据函数的要求来搜索(了解)
def name_is_exists(tag):
return tag.has_attr('name')
t_list = bs.find_all(name_is_exists)
kwargs:
t_list = bs.find_all(id="head")
t_list = bs.find_all(class_=True)
参数值↑
text参数:
t_list = bs.find_all(text=["hao123","地图","贴吧"])
t_list = bs.find_all(text= re.compile("\d"))
可以用列表,也可以用正则表达式
limit参数
css选择器:
t_list = bs.select('title')#通过标签来查找
t_list = bs.select('.mnav')#通过类名查找
t_list = bs.select('#u1')#通过id查找
t_list = bs.select('a[class=“bri”]')#通过属性查找
t_list = bs.select('head > title')#通过子标签来查找
t_list = bs.select('.mnav ~ .bri')#通过兄弟类来查找。(和mnav是兄弟,且类为bri的标签)
re正则表达式
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。
多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
re.compile()
创建正则表达式对象,表示规则(字符串的模式)
import re
pat = re.compile("AA") #正则表达式
m = pat.search("ABCAA") #search字符串被校验的内容
m = re.search("AA","AbCAA")#简单写法↑
search进行比对查找。就找到第一个
m = re.findall("AA","AABCAA")
m = re.findall("[A-Z]+","ASDaFPGAa")#['ASD', 'FPGA']
findall找到所有的。
sub
re.sub('a','A','abcdefgcasd') 找到a,用A替换
建议在正则表达式中,被比较的字符串前面加上r,不用担心转义字符的问题
sqlite3
社区版(已放弃尝试)
安装插件 database navigator。就可以看db文件啦!
打开db Browser,新建数据库。将自己的db文件代替sqlite.db。
单击Test Connection。
如果提示:
Invalid or incomplete database configuration:
- Database information incomplete or invalid (host, port, database, file)是因为点击添加,在新的一行输入路径
解决:直接将第一行的sqlite.db修改为数据库文件路径
添加完之后,点Apply,下载资源!
import sqlite3
conn = sqlite3.connect('test.db')#打开/创建
# print('Opened database successfully')
print("成功打开数据库")
c = conn.cursor()#获取游标
sql = '''
create table company
(id int primary key not null,
name text not null,
address char(50),
salary real);
'''
c.execute(sql) #执行sql语句
conn.commit() #提交数据库操作
conn.close()
print("成功建表")
建完表之后刷新
专业版
建立表
import sqlite3
conn = sqlite3.connect('test.db')#打开/创建
# print('Opened database successfully')
print("成功打开数据库")
c = conn.cursor()#获取游标
sql = '''
create table company
(id int primary key not null,
name text not null,
age int not null,
address char(50),
salary real);
'''
c.execute(sql) #执行sql语句
conn.commit() #提交数据库操作
conn.close()
print("成功建表")
插入数据:
把sql换成
sql = '''
insert into company(id,name,age,address,salary)
values (1,'张三',32,'成都',8000),
(2,'李四',40,'北京',20000);
'''
查询数据:
import sqlite3
conn = sqlite3.connect('test.db')#打开/创建
print("成功打开数据库")
c = conn.cursor()#获取游标
sql='''
select id,name,address,salary from company
'''
cursor = c.execute(sql)
for row in cursor:
print('id=',row[0],'name=',row[1],'address=',row[2])
conn.close()
右键表格,编辑源码,可以测试sql语句
其它个人笔记
json.loads()
:把json文件转成字典格式。
data = json.loads(srcData)
B站,个人主页。可以爬取所有投稿信息:
https://api.bilibili.com/x/space/arc/search?mid=【作者id】&ps=30&tid=0&pn=【页数】&keyword=&order=pubdate&jsonp=jsonp
B站,视频播放页。可以爬取评论信息:
https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=1&oid=【aid,av号】&mode=3&plat=1&_=
excel异步保存,追加数据
import xlwt # 读取
import xlrd #写入
from xlutils.copy import copy
文件头我用另一个函数初始化了。
def saveData(savepath,datalist):
book = xlrd.open_workbook(savepath)
sheets = book.sheet_names() # 获取工作簿中的所有表格
worksheet = book.sheet_by_name(sheets[0]) # 获取工作簿中所有表格中的的第一个表格
rows_old = worksheet.nrows
new_workbook = copy(book) # 将xlrd对象拷贝转化为xlwt对象
new_worksheet = new_workbook.get_sheet(0)
for index in range(len(datalist)):
print(f'正在保存第{index+rows_old}条')
data = datalist[index]
print(data)
for p in range(len(data)):
new_worksheet.write(index+rows_old,p,data[p])
new_workbook.save(savepath)