爬取对象:https://movie.douban.com/top250(注:最新更新于 网站信息肯能会有变化导致信息爬取失败)
爬取的基本步骤:
①将计算机访问行为模拟成用户行为(UA的模拟以及爬取时间间隔设置)
②对要爬取的网页进行分析
③获取整个网页的源码并用特殊的解析器解析
④运用正则表达式提取整理所需要的数据
⑤将爬取到的数据储蓄到Excel表格
模拟用户行为进行页面信息获取
进行一个页面信息的获取,我们需要用到requests 库中的get方法
page = requests.get(url=dburl, headers=header) #访问的网址储蓄在dburl中 所用的ua标识为header(ua标识将在下面介绍)
html = ""
html = page.text #要将获取到的网页转为字符串形式后放在变量html中
User_agent(简称UA)是计算机访问浏览器时所自带的一个标识,可以让页面直到你是在用计算机访问
我们可以通过浏览器按F12来查看我们通过相应浏览器访问的User_agent
也可以引入库 my_fake_useragent 实现自动匹配不同的ua设置
因为需要和requests.get()方法所需要的格式相同,所以我们采用下面格式:
header1 = {
'User-Agent': '直接将在浏览器中找打的UA复制过来,注意换行'
} #方法一:直接复制自己的UA
header = {
'User-Agent': my_fake_useragent.UserAgent().random()
} #方法二:运用my_fake_useragent随机导入ua
其次我们可以模仿的是爬取网页中的时间间隔
我们引入random 库生成随机暂停的秒数 引入time库进行暂停操作
a = random.uniform(0,0.5) #随机生成一个0~0.5之间的数
a = round(a,4) #保留四位小数
time.sleep(a) #程序暂停a秒
注:尽管这样过于频繁的爬取还是会让自己的ip地址被豆瓣禁用,所以这里新手做多次测试的时候可以将爬取到的数据信息保存到本地
with open('结果存放.txt',"w", encoding='utf-8') as f: # .txt可以不自己新建,代码会自动新建
f.write(html) # 写入
f.write('\n') # 有时放在循环里面需要自动转行,不然会覆盖上一条数据
f.close()
这样他就会在代码所在的文件夹中建立存放结果.txt储蓄爬取到的结果,之后可以直接通过读取相关文件进行后续代码的测试
之后读取可以通过
with open("结果存放.txt", "r",encoding='utf-8') as f:
html = f.read()
将缓存的结果存放.txt重新读取回html中
关于运用python进行文件读取打开的相关文章借鉴:https://blog.csdn.net/weixin_39826080/article/details/110138177
这样我们就写好了获取一个网页数据的代码:
def get_html(dburl) :
a = random.uniform(0, 0.5)
a = round(a, 4)
time.sleep(a)
header = {
'User-Agent': my_fake_useragent.UserAgent().random()
}
page = requests.get(url=dburl, headers=header)
html = ""
html = page.text
# print(html) #可以用来检测自己获取到的数据是否正确
return html
# with open('结果存放.txt',"w", encoding='utf-8') as f:
# f.write(html)
# f.write('\n')
# f.close()
对于要爬取的网页进行初步分析
点入豆瓣电影排名250第二页后,我们看到此时网站变成:https://movie.douban.com/top250?start=25&filter=
大胆将&filter=删去,按回车发现网页仍能加载,如此删去一个网址中无用的信息,再点击第三页后发现start后面的数字变成了50
因此可以知道start后面的值是该页面第一步电影的序列号(经过试验后该猜想得到证实)
baseurl = 'https://movie.douban.com/top250'
datelist = [] #表格用于储蓄所有电影的信息
for i in range(0, 10):
dburl = baseurl + "?start="+str(i * 25)
html = get_html(dburl) # 保存获取到的网页信息源码
# 开始逐一解析数据
# print(html)
因此,我们可以通过for循环进行全部250部电影的数据爬取(一页一页的进行爬取)
网页解析以及特定数据的查找
运用beautifulsoup库中的html.parser解析器进行网页数据的解析
运用re库的查找功能配合正则表达式进所需数据的查找
经过之前测试打印出来的第一页网页数据,我们发现每一部电影信息都在一块class_="item"中,所以我们先用re库中find_all方法找到一个电影模块作为一个模块item,再在这个item中寻找相关信息:
bs = BeautifulSoup(html, "html.parser")
for item in bs.find_all('div', class_="item"): # 查找符合要求的字符串,形成列表
datem = [] # 储蓄一部电影的所有信息
item = str(item) #注意要将item字符串化
link = re.findall(findlink, item)[0] # re库用来通过正则表达式查找指定的字符串,只要一个模块中的第一个
datem.append(link) #将获取到的内容存入datem列表当中
这段代码中提到的 link = re.findall(findlink, item)[0] 是指在item中运用findlink的正则表达式规则找数据,将找到的第一个放到link中。
findlink(一般放在全局变量中比较了然)的准则指定我们则需要运用到正则表达式的知识
正则表达式
本文仅介绍本文所要使用的部分 详细可以参考:https://deerchao.cn/tutorials/regex/regex.htm
此时,我们想要爬取到电影链接的数据:
可以知道我们所需要的数据在<a href=" ">
中
此时,我们可以用(.*?)表示内部链接内容,而这部分正则符号表示的数据,也正是其会返回的数据
r''表示忽略所有特殊的字符以防查找的时候出错
最后最好加上re.S(注意一定要大写) 这会让正则检索的时候忽略换行或者空格造成的数据检索障碍问题
详情参考:https://www.cnblogs.com/moning/p/8296893.html
(.表示除换行符外的任何字符 *表示匹配前一个字符的零次或者无限次 *加上?表示非贪婪模式,取到一个符合的数据就返回)
findlink = re.compile(r'<a href="(.*?)">', re.S) # compile创建正则表达式对象,圆括号中表示规则(此次为字符串的模式)
如上,我们可以得到其他诸如图片链接、影片名字、介绍、详情等信息,他们的正则搜索规则如下
findimgsrc = re.compile(r'<img alt=".*" class="" src="(.*?)" width="100"/>', re.S)
findname = re.compile(r'<span class="title">(.*?)</span>')
findpeopel = re.compile(r'<span>(\d*)人评价</span>') #这边表示的是全是数字的情况
findbd = re.compile(r'<p class="">(.*?)</p>', re.S)
findinq = re.compile(r'<span class="inq">(.*?)</span>')
然后依次将数据存到datem列表当中:
imgsrc = re.findall(findimgsrc, item)[0]
datem.append(imgsrc)
judgenumber = int(re.findall(findpeopel, item)[0])
datem.append(judgenumber)
inq = re.findall(findinq, item)
if len(inq) != 0:
inq = inq[0].replace("。", "") # 删掉句子中的句号
datem.append(inq)
else:
datem.append(" ")
bd = re.findall(findbd, item)[0]
bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd) # 用空格替换得到的br数据(\s+)?是为了防止有多个空格
bd = re.sub("/", " ", bd)
bd = re.sub("\xa0", " ", bd)
datem.append(bd.strip()) # 去掉前后空格
datelist.append(datem)
对于找到数据的进一步处理
对于得到的数据,还有一些问题等待我们去处理
比如说关于电影名字有些电影是有英文名字的,而有些没有,我们需要进行如下处理:
title = re.findall(findname, item) #此时我们不添加[0]表示两个电影名字我们都读取
if (len(title) == 2): #如果有两个名字
ctitle = title[0] # 添加中文名
datem.append(ctitle)
title[1] = title[1].replace("\xa0", "") # 对于爬取到电影数据杂质的去除
etitle = title[1].replace("/", "")
datem.append(etitle)
else: #如果只有一个电影名
datem.append(title[0])
datem.append(" ") # 就算没有也要留空,方便后续制作成表格
因为爬取到的数据可能含有一些我们不需要的内容,比如说大量的空格符号,斜杠等。
此时就需要我们的.replace(“要替换的符号”,“替换成什么符号”)方法出场
除了.replace()方法,我们还可以通过re库的sub方法进行替换:
bd = re.findall(findbd, item)[0]
bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd) # 用空格替换得到的br数据(\s+)?是为了防止有多个空格(此处为正则表达式)
bd = re.sub("/", " ", bd)
bd = re.sub("\xa0", " ", bd)
datem.append(bd.strip()) # 去掉前后空格后再加入
保存到excle表格中
导入xlwt库
此时,我们已经将250部电影数据全部保存在了datelist中 ,新手可以先将datelist通过josn格式的文件保存到本地方便后续的反复测试:
保存:
with open('datelist.json', 'w', encoding='utf-8') as f:
json.dump(datelist, f)
读取:
with open('datelist.json', encoding='utf-8') as f:
datelist = json.load(f)
通过printf等手段确定datelist中的数据无误后可以进行数据的保存
构造以下函数,输入参数为datelist数组已经保存的路径:
def saveDate(datelist,savepath):
print("save.....") #显示已经进入保存函数界面,信息交互,可删
book = xlwt.Workbook(encoding="utf-8")#创建excle表格文件
sheet = book.add_sheet('豆瓣电影top250',cell_overwrite_ok=True)#创建数据表单,每个单元再写入的时候可以覆盖以前的内容
col=("介绍链接","图片链接","电影名字","电影原名","评分人数","电影介绍","详情") #对第一行进行行表定义(我们爬取到的数据)
for i in range(0,7):
sheet.write(0,i,col[i])#把col数列作为第一栏的标题写入
for i in range(0,250):#剩余数据的传入
print("第%d条" %i)
date = datelist[i]
for j in range(0,7):
sheet.write(i+1,j,date[j])
book.save(savepath)#保存文件
经过上述操作后我们可以在程序所在的文件中发现新出现的豆瓣电影top250.xlsx文件
最简单的一个爬虫数据就完成了,一下为完整代码:
import requests
from bs4 import BeautifulSoup
import re
import time
import my_fake_useragent as ua
import random
import xlwt
def get_html(url) :
a = random.uniform(0, 1)
a = round(a, 4)
time.sleep(a)
header = {
'User-Agent': ua.UserAgent().random()
}
page = requests.get(url=url, headers=header)
html = ""
html = page.text
# print(html)
return html
# with open('结果存放.txt',"w", encoding='utf-8') as f: # .txt可以不自己新建,代码会自动新建
# f.write(html) # 写入
# f.write('\n') # 有时放在循环里面需要自动转行,不然会覆盖上一条数据
# f.close()
findlink = re.compile(r'<a href="(.*?)">') # compile创建正则表达式对象,表示规则(字符串的模式)
findimgsrc = re.compile(r'<img alt=".*" class="" src="(.*?)" width="100"/>', re.S)
findname = re.compile(r'<span class="title">(.*?)</span>')
findpeopel = re.compile(r'<span>(\d*)人评价</span>')
findbd = re.compile(r'<p class="">(.*?)</p>', re.S)
findinq = re.compile(r'<span class="inq">(.*?)</span>')
def saveDate(datelist,savepath):
print("save.....")
book = xlwt.Workbook(encoding="utf-8")#创建book对象
sheet = book.add_sheet('豆瓣电影top250',cell_overwrite_ok=True)#创建数据表单,每个单元再写入的时候可以覆盖以前的内容
col=("介绍链接","图片链接","电影名字","电影原名","评分人数","电影介绍","详情")#对第一列进行列表定义
for i in range(0,7):
sheet.write(0,i,col[i])#把col数列作为第一栏的标题写入
for i in range(0,250):#剩余数据的传入
print("第%d条" %i)
date = datelist[i]
for j in range(0,7):
sheet.write(i+1,j,date[j])
book.save(savepath)#保存文件
if __name__ == '__main__':
baseurl = 'https://movie.douban.com/top250'
datelist = [] #储蓄所有电影的信息
for i in range(0, 10):
url = baseurl + "?start="+str(i * 25)
html = get_html(url) # 保存获取到的网页信息源码
# 开始逐一解析数据
# print(html)
bs = BeautifulSoup(html, "html.parser")
for item in bs.find_all('div', class_="item"): # 查找符合要求的字符串,形成列表
datem = [] # 储蓄一部电影的所有信息
item = str(item)
link = re.findall(findlink, item)[0] # re库用来通过正则表达式查找指定的字符串,只要一个模块中的第一个
datem.append(link)
imgsrc = re.findall(findimgsrc, item)[0]
datem.append(imgsrc)
title = re.findall(findname, item) # 有两个名字,一个中文的一个外语(网页分析得)
if (len(title) == 2):
ctitle = title[0] # 添加中文名
datem.append(ctitle)
title[1] = title[1].replace("\xa0", "") # 把获取到的信息中的/替换掉 添加外国名
etitle = title[1].replace("/", "")
datem.append(etitle)
else:
datem.append(title[0])
datem.append(" ") # 就算没有也要留空
judgenumber = int(re.findall(findpeopel, item)[0])
datem.append(judgenumber)
inq = re.findall(findinq, item)
if len(inq) != 0:
inq = inq[0].replace("。", "") # 删掉句子中的句号
datem.append(inq)
else:
datem.append(" ")
bd = re.findall(findbd, item)[0]
bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd) # 用空格替换得到的br数据(\s+)?是为了防止有多个空格
bd = re.sub("/", " ", bd)
bd = re.sub("\xa0", " ", bd)
datem.append(bd.strip()) # 去掉前后空格
datelist.append(datem)
print(datem)
savepath = "test.xls"
saveDate(datelist,savepath)