c 抓取网页数据(Python静态网页抓取学习过程及一点简单的分析保存方法)
优采云 发布时间: 2022-04-12 05:38c 抓取网页数据(Python静态网页抓取学习过程及一点简单的分析保存方法)
Python 静态网页抓取
最近学习了使用Python爬虫爬取静态网页,做一点简单的分析保存。以下是整个学习过程:
实践要求的目的
访问豆瓣电影Top250网站,抓取所有电影的片名、导演、主演、上映年份、电影分级和评分。并将结果保存到 Excel。
爬取过程 爬取网页
使用Python中的requests库,可以直接爬取网页源代码。
我们首先使用DOS来安装requests
pip install --user requests
根据百度上的pip安装教程,使用pip安装时,直接输入pip install +(库名),但无法安装成功。根据内置提示,添加--user即可成功安装。
在 Python 中导入请求后,使用库函数 get 直接获取网页的源代码。
link = 'https://movie.douban.com/top250'
r = requests.get(link,headers,timeout=20)
在获取函数中:
让我们仔细看看最后两个参数。
请求标头为我们提供有关请求、响应或其他发送实体的信息。如果没有请求头或者请求头没有正确对应网页,那么我们抓取的结果可能是错误的。
如何找到网页的请求头?
我们进入豆瓣电影top250的网页,按f12进入开发者模式;
单击网络并刷新界面。
点击网页名称,然后点击Headers,我们可以在其中找到请求头的内容,并按照如下格式保存在Python中。
headers ={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
'Host':'movie.douban.com'}
说完请求头,再来说说响应时间的设置。
因为有时候爬虫会遇到服务端长时间不响应不返回的情况,那么爬虫就会等待,我们设置一个无响应返回的时间,如果时间截止点还没有返回回应。
接下来我们会发现上面的链接只有25部电影,总共250部电影分布在10个页面上;我们点击第二页,发现URL变了:;第三页:;再多一页,在链接的最后一个数字上加 25。
我们可以设置一个for循环来不断更新爬取的网页。
for i in range (0,10):
link = 'https://movie.douban.com/top250?start=' + str(i*25)
r = requests.get(link,headers=headers,timeout=20)
至此,我们可以检查上述过程是否正确,是否爬取成功。
我们打印出每一页的响应状态码。
print('Page',i,' ',r.status_code)
当状态码为200时,爬取成功。
分析网页
经过上面的过程,我们就可以得到网页的HTML代码了,但是我们不需要这么多东西,我们需要分析并从中提取出我们想要的东西。
我们需要使用第三方库bs4中的BeautifulSoup;
通过 pip 安装和导入,方法同上。
pip install --user bs4
from bs4 import BeautifulSoup #导入
BeautifulSoup 可以自动将输入文档转换为 Unicode 编码,将输出文档自动转换为 utf-8 编码。BeautifulSoup可以将html解析成对象进行处理,并将所有页面转换成字典或数组,相比正则表达式可以大大简化处理过程。
我们创建一个 BeautifulSoup 对象汤来解析网页。
soup = BeautifulSoup(r.text,"lxml")
这里的lxml是Python解析HTML页面的库,是BeautifulSoup解析的固定搭配之一。(这里如果代码报错,可能是因为没有安装lxml库,用pip安装就行了。)
我们先通过浏览器的开发者模式观察发现
电影名称保存在 div 标签下的 class="hd" 中,我们需要的其他信息保存在 div 标签下的 class="bd" 中。
我们首先讨论电影标题的提取。其余项目基本类似。
我们直接使用soup中的find_all函数。汤里有两个函数,一个是find,一个是find_all。find函数返回第一个满足搜索条件的结果,find_all返回所有结果。这里我们根据需要使用 find_all。,并将结果保存到列表中。
div_list1 = soup.find_all('div',class_='hd')
这里会打印列表,并截取第一个“肖申克的救赎”的结果,即div_list[0]。同时,我们将对比豆瓣网页源代码的形式。我们可以提取名称。
电影名称存储在标签 a 下方的第一个跨度标签中。使用循环将所有电影的名称保存在第一页上。
for each in div_list1:
#中文名
movie_name = each.a.span.text.strip()
movies_name.append(movie_name)
这里 movies_name 是一个收录所有电影名称的列表。
这样我们就保存了整个 top250 电影的名称。让我们输出它来检查。
后续其他项目的流程基本相同。
我们将 find_all 函数中的第二个参数替换为:class="bd" 并将其保存在一个列表中。
问题来了。我们需要的内容不是保存在a和span中,而是保存在一个标签p中。如果我们直接用p替换a,跳过span部分,报错!,怎么办?
我们需要用另一个函数来替换它:contents,contents可以输出p下面的所有内容,并返回一个列表。我们现在可以在这个列表中找到我们需要的东西。
我还是先输出吗
div_list2=soup.find_all('div',class_='bd')
的结果。(为了方便观察,我们直接用断点+单步调试的方法查看结果)
我们需要从 div_list2 的第二项开始,所以循环应该从 div_list2[1] 开始。
只有 each.p.contents 中的第一项和第三项是我们需要的,所以我们列表的底部确定为 contents[0] 和 contents[2]。
我们先谈谈内容[0]。我们通过strip函数和split函数对字符串进行处理,去掉一些杂项。
movie = each.p.contents[0].strip().split('\xa0')
当当,结果出来了。
当我们输出所有结果时,发现有问题。错误!或者是数组越界的错,为什么是这个时候?显然第一个提取成功了,第二个也成功了。
再来看看豆瓣的网站
最后,它并没有显示全部。也就是说,后面的一部电影导演太多,或者名字太长的时候,主角就变成了“……”,无法展现。最重要的是上面movie返回的list长度从4变成了4。 2、当我们尝试使用上面的
actor = movie[3]
,自然会报错。
如何解决这个问题?
这个问题我其实还没有从根本上解决,因为这是豆瓣网页的问题,不能添加html中没有的词,除非我点击每个电影链接查看,但是这250个的具体细节movies 链接之间没有直接关联,也许有办法提取新的URL,从而重新爬取新的URL,然后分析,然后得到。从这个方向思考,似乎太麻烦了。
包括以上,有人可能会怀疑我提取了中文电影名,为什么不提取英文名和港台名。这里挖了一个小坑。有兴趣的可以尝试提取英文名和港台名。
当然,也有可能是我的水平不够,不知道有什么厉害的方法。
这里我们直接使用if判断语句根据电影的长度来判断。
if len(movie)==4:
movie_dir = movie[0][4:]
movie_actor = movie[3][4:]
else:
movie_dir = movie[0][4:]
movie_actor = '...'
其余部分没有坑。按照上述步骤,您可以提取电影的发行年份、国家、分类和评级。此处不再赘述。
保存数据
所有数据都被提取和分析,并保存在movies_name、movies_dir、movies_actor、movies_time、movies_nation、movies_class、movies_grade的列表中。接下来就是如何保存到Excel中了,方便我们进行进一步的工作。
为了保存到 excel,我们使用与 Python 和 Excel 关联的库 xlwt。
xlrd和xlwt这两个库在Python文件操作中与Excel关联,分别对应Excel的读写。写在这里,使用 xlwt。可以直接通过pip安装。
直接使用xlwt的功能:
workbook = xlwt.Workbook(encoding = 'utf-8')
worksheet = workbook.add_sheet('豆瓣top250')
xlwt.Workbook(encoding = 'utf-8') - 创建一个 utf-8 编码的 Excel 工作表。
add_sheet('Douban top250') - 在sheet中创建一个名为“Douban top250”的工作簿。
一旦建立,下一步就是写入数据。只需使用一个功能。
worksheet.write(r,c,str)
其中,r代表行,c代表列,str代表内容。
只需依次存储我们列表的内容。
最后,保存 Excel:
保存(文件名)
filename 是保存文件的路径。
统计结果(部分)
完整代码下载