爬虫入门教程⑨— 用html和csv文件保存爬取到的数据

经过努力,我们终于拿到了数据了。那么下一步就是要将我们获取到的数据保存起来了,这样才能给后续的操作(在网页上展示、数据分析挖掘可视化等等)提供便利。

一般我们保存数据可以采用多种可选载体,根据成本、数据用途我们分别采用适合自己的载体保存数据。

  • 主要的数据保存方法有
    • 写入到文本:txt,csv,excel...
    • 保存到数据库:本地的sqlite、MySQL、mongodb...

由于保存到数据库的操作需要了解数据库相关知识以及软件支持,所以我们本章采用多种文本方式写入。

先回顾一下上一节的代码:

import requests
from bs4 import BeautifulSoup  # 从bs4引入BeautifulSoup

#请求网页
# 旧版教程
# url = "https://movie.douban.com/cinema/later/chengdu/"
# response = requests.get(url)

# 2019-12-23更新,解决不能获取到响应的问题
url = "https://movie.douban.com/cinema/later/chengdu/"  # URL不变
# 新增伪装成Chrome浏览器的header
fake_headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
}
response = requests.get(url, headers=fake_headers)  # 请求参数里面把假的请求header加上

# 解析网页
# 初始化BeautifulSoup方法一:利用网页字符串自带的编码信息解析网页
soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml')
# 初始化BeautifulSoup方法二:手动指定解析编码解析网页
# soup = BeautifulSoup(response.content, 'lxml', from_encoding='utf-8')

# print(soup)  # 输出BeautifulSoup转换后的内容
all_movies = soup.find('div', id="showing-soon")  # 先找到最大的div
# print(all_movies)  # 输出最大的div的内容
for each_movie in all_movies.find_all('div', class_="item"):  # 从最大的div里面找到影片的div
    # print(each_movie)  # 输出每个影片div的内容
    all_a_tag = each_movie.find_all('a')
    all_li_tag = each_movie.find_all('li')
    movie_name = all_a_tag[1].text
    moive_href = all_a_tag[1]['href']
    movie_date = all_li_tag[0].text
    movie_type = all_li_tag[1].text
    movie_area = all_li_tag[2].text
    movie_lovers = all_li_tag[3].text
    print('名字:{},链接:{},日期:{},类型:{},地区:{}, 关注者:{}'.format(
        movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers))
  • Python打开文件操作详解
    使用file_obj = open("file_name", 'mode', encoding="encoding")的方法进行操作。
    file_name是你需要读取或者写入的文件路径及文件名("../data/ok.txt"是相对路径打开,如果只写一个"ok.txt",那么就会默认保存到当前.py文件或者.ipynb文件的相同文件夹里面)

    • mode是你指定操作文件的方法,常用的有rwa, r+rbwbabrb+这些方法,r是读取(read,如果不存在则报错),w是写入(write,文件不存在则创建,如果文件存在则覆盖),a是追加写入(文件不存在则创建,文件存在从文件最后开始写入),r+是读取和写入。后面加了个b的,是以二进制方式进行上述操作(通常用于对图片、视频等二进制文件进行操作),mode默认是r。

    • encoding在前面的章节说过了,是我们对文件进行操作所遵循的编码,默认为当前运行环境编码。Windows的默认编码是gbk,linux系统基本上是utf-8。不同的文件可以有不同的编码,设置读取的编码错误要么会报错,要么就得不到正确的内容。

    • file_obj是一个文件对象(Python里面也是万物皆对象,所以不要愁没有对象了),之后我们读取、写入数据都通过这个对象进行操作。

  • Python读取文件方法
    file_obj.read(),一次性读取文件所有的内容作为一个字符串。
    file_obj.readlines(),一次性读取文件所有内容,但每一行作为一个字符串并放在一个list(数组)里面。
    file_obj.readline(limit),从上次读取的行数开始,读取limit行,limit默认为1。该方法通常用在由于文件过大不能一次性读取完毕一个文件的时候)。

  • Python写入文件的方法
    file_obj.write(anystr),该方法接受一个字符串,并将字符串写入。
    file_obj.writelines(list_of_str),该方法接受一个内部全是字符串的list数组,并将所有字符串一行一个写入(自动添加换行符)。

  • 关闭文件
    file_obj.close() 关闭文件对象。打开了一个文件之后要记得关闭,否则可能会出现不可控的问题。但是如果用with方法打开了文件,则不需要手动关闭文件,在with语句块运行结束后,会自动关闭文件。
    示例

# 需要手动关闭文件
file_obj = open("ok.txt", 'r', encoding="utf-8")
content = file_obj.read()
file_obj.close()

# 不需要手动关闭文件
with open("ok.txt", 'r', encoding="utf-8") as file_obj:
    content = file_obj.read()

 

把数据保存到 html 文件

由于txt文件难度较低且所学内容被本小节囊括了,所以我们直接从保存数据到HTML文件开始。
我们的目标是:


网页示例

上面这个截图的网页的代码是这样的(为了简洁美观,所以采用了bootstrap的css样式):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>豆瓣电影即将上映影片信息</title>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h2 class="text-center">豆瓣电影即将上映影片信息</h2>
<table class="table table-striped table-hover mx-auto text-center">
    <thead>
        <tr>
            <th>影片名</th>
            <th>上映日期</th>
            <th>影片类型</th>
            <th>地区</th>
            <th>关注者数量</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><a href="https://movie.douban.com/subject/30212331/">测试名1</a></td>
            <td>测试日期1</td>
            <td>测试类型1</td>
            <td>测试地区1</td>
            <td>测试关注者1</td>
        </tr>
        <tr>
            <td><a href="https://movie.douban.com/subject/30212331/">测试名2</a></td>
            <td>测试日期2</td>
            <td>测试类型2</td>
            <td>测试地区2</td>
            <td>测试关注者2</td>
        </tr>
    </tbody>
</table>
</body>
</html>

从这个代码,我们可以知道,只要我们重复生成<tbody>标签里面的<tr>...<tr>中间的内容,并把我们的数据填进去,数据就会一行一行地被填充到表格中了。<tbody>前后的代码我们就只需要复制过来写入就好了。
所以我们就拿着之前的代码开始操作了:
注:python 里面三个"围起来的字符会被看做是一整个字符串,避免了换行符的麻烦。
.format()这个方法的用法是把字符串里面的{}字符,按次序一一替换成 format() 接受的所有参数。

import requests
from bs4 import BeautifulSoup  # 从bs4引入BeautifulSoup

#请求网页
# 旧版教程
# url = "https://movie.douban.com/cinema/later/chengdu/"
# response = requests.get(url)

# 2019-12-23更新,解决不能获取到响应的问题
url = "https://movie.douban.com/cinema/later/chengdu/"  # URL不变
# 新增伪装成Chrome浏览器的header
fake_headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
}
response = requests.get(url, headers=fake_headers)  # 请求参数里面把假的请求header加上

 # 初始化BeautifulSoup方法一:利用网页字符串自带的编码信息解析网页
soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml') 

# 初始化BeautifulSoup方法二:手动指定解析编码解析网页
# soup = BeautifulSoup(response.content, 'lxml', from_encoding='utf-8') 

# print(soup)  # 输出BeautifulSoup转换后的内容
all_movies = soup.find('div', id="showing-soon")  # 先找到最大的div
# print(all_movies)  # 输出最大的div的内容

html_file = open('data.html', 'w', encoding="utf-8")
html_file.write("""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>豆瓣电影即将上映影片信息</title>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h2 class="text-center">豆瓣电影即将上映影片信息</h2>
<table class="table table-striped table-hover mx-auto text-center">
    <thead>
        <tr>
            <th>影片名</th>
            <th>上映日期</th>
            <th>影片类型</th>
            <th>地区</th>
            <th>关注者数量</th>
        </tr>
    </thead>
    <tbody>
""")
for each_movie in all_movies.find_all('div', class_="item"):  # 从最大的div里面找到影片的div
    # print(each_movie)  # 输出每个影片div的内容
    all_a_tag = each_movie.find_all('a')
    all_li_tag = each_movie.find_all('li')
    movie_name = all_a_tag[1].text
    moive_href = all_a_tag[1]['href']
    movie_date = all_li_tag[0].text
    movie_type = all_li_tag[1].text
    movie_area = all_li_tag[2].text
    # 替换字符串里面的 想看 两个字为空,使得更加美观
    movie_lovers = all_li_tag[3].text.replace("想看", '')
    print('名字:{},链接:{},日期:{},类型:{},地区:{}, 关注者:{}'.format(
        movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers))
    html_file.write("""
        <tr>
            <td><a href="{}">{}</a></td>
            <td>{}</td>
            <td>{}</td>
            <td>{}</td>
            <td>{}</td>
        </tr>
    """.format(moive_href, movie_name, movie_date, movie_type, movie_area, movie_lovers))
html_file.write("""
     </tbody>
</table>
</body>
</html>
""")
html_file.close()
print("write_finished!")

运行一下,成功输出。然后我们回到 jupyter 的首页,找到我们的data.html,点击文件名打开网页,就可以看到如下的结果了,并且我们点击这些影片的名字,都会自动跳转到影片的详情页。

写入结果展示


 

数据保存到csv文件

首先介绍一下csv文件,这是个类 txt 的表格文件,读取和写入都相对excel的表格文件更加简单方便,所以在数据领域使用较多。
要使用csv模块,我们首先需要import csv,然后把一个文件对象作为参数传给csv.writer()或者csv.reader(),然后我们就对这个writer/reader进行读写操作了。
写入是调用writer的writerow()方法。writerow方法接受一个由字符串组成的 list 数组,然后就会把这个list的内容按照规定写入到csv文件。
读取则是对reader进行遍历,每一轮遍历的结果返回一行的数据组成的 list数组。

写入示例:

import csv
# Windows默认编码是gbk,如果用utf-8,excel打开可能会乱码
# newline='' 是为了让writer自动添加的换行符和文件的不重复,防止出现跳行的情况
file_obj = open('csvtest.csv', 'w', encoding="gbk", newline='')
writer = csv.writer(file_obj)
a_row = ['你好', 'hello', 'thank', 'you']
row_2 = ['how', 'are', 'you', 'indian', 'mifans']
writer.writerow(a_row)
writer.writerow(row_2)
file_obj.close()
print('finished!')

我们在Windows文件管理器打开当前代码文件夹,(如果没有指定jupyter启动路径并且是以win+x键启动的jupyter,那么jupyter的代码和生成的文件默认是在你的 C:/USER(用户)/username 文件夹里面,username是你的电脑的用户名。)
找到这个csvtest.csv文件(默认就是excel或者wps格式)并打开

运行结果用excel打开

其实文件内容很简单:用,隔开不同的列,一行就是一个新的行:

csv文件内容

读取示例:

import csv
# 读取的编码要和写入的保持一致
file_obj = open('csvtest.csv', 'r', encoding="gbk")
reader = csv.reader(file_obj)
for row in reader:
    print(row)
file_obj.close()
print('finished!')

运行结果输出:

['你好', 'hello', 'thank', 'you']
['how', 'are', 'you', 'indian', 'mifans']
finished!

OK,下一步我们就试着把影片信息存到csv文件中

import csv
import requests
from bs4 import BeautifulSoup  # 从bs4引入BeautifulSoup

# 请求网页
url = "https://movie.douban.com/cinema/later/chengdu/"
response = requests.get(url)
# 初始化BeautifulSoup方法一:利用网页字符串自带的编码信息解析网页
soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml')

# 初始化BeautifulSoup方法二:手动指定解析编码解析网页
# soup = BeautifulSoup(response.content, 'lxml', from_encoding='utf-8')

# print(soup)  # 输出BeautifulSoup转换后的内容
all_movies = soup.find('div', id="showing-soon")  # 先找到最大的div
# print(all_movies)  # 输出最大的div的内容

csv_file = open('data.csv', 'w', encoding="gbk", newline='')
writer = csv.writer(csv_file)

writer.writerow(["影片名", "链接", "上映日期", "影片类型", "地区", "关注者"])  # 写入标题
for each_movie in all_movies.find_all('div', class_="item"):  # 从最大的div里面找到影片的div
    # print(each_movie)  # 输出每个影片div的内容
    all_a_tag = each_movie.find_all('a')
    all_li_tag = each_movie.find_all('li')
    movie_name = all_a_tag[1].text
    moive_href = all_a_tag[1]['href']
    movie_date = all_li_tag[0].text
    movie_type = all_li_tag[1].text
    movie_area = all_li_tag[2].text
    movie_lovers = all_li_tag[3].text.replace("想看", '')
    print('名字:{},链接:{},日期:{},类型:{},地区:{}, 关注者:{}'.format(
        movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers))
    writer.writerow([movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers])

csv_file.close()
print("write_finished!")

用excel打开的结果

以上就是一部分常见的对数据的保存方式了。如果能够对你学习Python与爬虫的过程起到一点微小的作用,那将是我的无比荣幸。感谢观看。


 
传送门:

下一章:

所有的章节:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 概述 java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。java.io ...
    Steven1997阅读 9,160评论 1 25
  • @宜风 我有一束光明明晃晃 我有一片心飘飘荡荡 我有一缕情惆惆怅怅 我有一个梦纷纷扬扬 光 透过心 穿过情 以梦为...
    邹颖一阅读 496评论 5 2
  • 首先要讲一下几个理念性的东西,我自己的理解,或许大家不赞同。不过赞不赞同另当别论,反正我这儿是得先说的。先说说我自...
    cOoKiE_1阅读 933评论 1 7
  • 码头的大喇叭: “云丸号上的士兵们,你们误会了,我们不是不送你们回日本。云丸号,在海上服役多年,机器老化,抗风能力...
    风起龙飞阅读 174评论 0 3