盒子
盒子
文章目录
  1. 爬虫简介
  2. 反爬虫简介
    1. 爬虫的首要目标-正确获取到数据
    2. 爬虫的进阶目标-优秀的爬取策略
    3. 爬虫的高级目标-数量少却高效的代码
  3. http请求
    1. response
    2. 综合知识
  4. 网页的构成
    1. HTML
    2. CSS
    3. JS
  5. 安装Python
  6. 安装爬虫常用工具包
    1. jupyter简介
    2. requests简介
    3. lxml简介
    4. beautifulsoup简介
  7. jupyter和requests的初步使用
    1. jupyter的简单使用
    2. requests:HTTP for humans
    3. requests.session的使用
    4. 把从浏览器获取到cookie添加到session里来绕过登录
  8. BeautifulSoup解析豆瓣即将上映的电影信息
  9. 用HTML文件和csv文件保存爬取到的数据
    1. 把文件保存到HTML文件
    2. 数据保存到csv文件

一个小爬虫

爬虫简介

爬虫是什么:自动从网络上收集信息的一种程序。一整套关于数据请求、处理、存储的程序,这之间又设计到关于网络、数据结构的一些知识。详细的有数据的采集、处理、存储三方面的知识。
为什么会有爬虫呢:可以从网络上爬取到大量自己需要的数据。
我们在哪里用到爬虫:自动采集帖子、发帖、秒杀、抢购东西。
怎样才能学好爬虫:冷静、仔细、耐心、多写代码。

反爬虫简介

爬虫的首要目标-正确获取到数据

很多网站觉得自己的数据比较宝贵,会花时间去对付爬虫,从而达到保护自己数据的目的。通常采取的措施有:圆形验证码、限制访问速度、拖动滑块验证、选出图片中颠倒的文字、数据加密后传输。

爬虫的进阶目标-优秀的爬取策略

我们拿到一个目标之后,首先要做的,并不是开始盲目的写代码,而是制订爬取策略。
1、从哪个页面开始
2、怎么进入到我们的目标网页
3、如何从目标网页中解析出我们的目标数据
4、解析后的数据如何存储
5、如何防止页面重复爬取

爬虫的高级目标-数量少却高效的代码

同样的一个网站,不同的人写出来,会有不用的效率。
首先,非常重要的一个方面,就是经验,孰能生巧。
另一个可能就是辅助工具的选择,Python里面,写爬虫有很多非常优秀的库可以给大家使用。一定要记住不要重复造轮子
使用友好快捷的工具,是我们追寻的目标。这又是编程的艺术,简单优于复杂。

http请求

每一个完整的HTTP请求,都由一个request和一个response组成。

###request
request包括的内容有:
请求头:主要是请求的链接(URL)、客户端的(Cookie)、客户端的名字(UserAgent)、请求的方法(Method)、请求的参数(表单)。
请求的body:通常包含了一些要发送给服务器的数据,这些数据对用户是不可见的,不会显示在浏览器的地址栏里面。

response

响应也包括的响应头、响应的body。
在响应头里面通常有操作客户端Cookies的命令,增加cookie或者删除cookie,如果是跳转,那么会有一个跳转的目标网址,浏览器发现了,就会自动跳转到新的网址去。
响应的body是响应的内容了,比如说网页内容,js代码,css代码,文件等等。

综合知识

一个请求对应一个响应,构成了一个完整的 http请求。
常见状态码的含义:
200–请求成功
302–请求跳转
403–拒绝访问
404–找不到资源

网页的构成

如果把整个网页看做一个人的话,那么html就是这个人的骨肉,css则是好看的外表,JS则能让这个人成长,移动。

HTML

超文本标记语言,“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。
我们看到的整个源代码就是一个HTML文件,这个文件使我们发起请求,然后服务器返回给我们响应的一部分。浏览器收到响应后,开始解析HTML文件,采用从上到下的流程,逐步渲染页面。把内容显示出来。所以加载网页是一个有过程的,并不是迅速就能出现的。
HTML标签有很多歌节点(Tag、Node)组成。这些节点之间的关系有父子关系、兄弟关系。
父子关系:子节点被包括在父节点中。
兄弟关系:两个节点位于同一层级,比如我们的所有的p标签。
其中每个节点都可以有自己的一些属性,比如:class、href、src、id。这些属性决定了他们的特点:
class:通常情况下,我们用class为节点加上样式。
href:这是一个锚点,如果href的值是一个互联网地址,那么它就会呈现一个链接的样式。
src:一般我们在img和script标签中使用,用来引用图片或者js文件,它的值就是文件的地址。
id:id通常在一个网页是唯一的,为了便于给它加上一个特别的样式或者便于js找到它。

CSS

层叠样式表,是一种用来表现HTML或XML等文件样式的计算机语言。CSS不仅能静态的修饰网页,还可以配合各脚本语言动态的对网页各元素进行格式化。
CSS能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力。

JS

JavaScript是一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML网页上使用,用来给HTML网页增加动态功能。
JS是可以在浏览器里面运行的编程语言。它的特点:
1、JS可以在浏览器端进行运算
2、JS可以发起请求并更新网页(重点!)
JS可以在不刷新网页的前提下,向后台发起请求,然后单独更新某一段网页。我们称之为AJAX。我们常见的点击加载更多、页面划到页面底端自动加载更多、点击删除某个节点、点击刷新,都属于AJAX操作。这是爬虫常见的障碍知一

安装Python

为什么爬虫要用Python:
Python写代码速度快。Python自诞生以来,秉承的思想就是简单优于复杂,所以Python写代码效率极高,在众多Python强大的库的加持下,我们可以用短短的几十行代码写出来一个完整的Python爬虫程序。
Python学习成本低。Python的语法没有其他语言那么复杂,又因为是动态类型的语言,学习成本降低很多,能够更快地上手,更方便的学习。
Python可以在多平台运行。
Python是一门功能强大的语言,用Python可以做到很多事情。

安装爬虫常用工具包

  • jupyter(简单方便的写代码工具)
  • requests(Python HTTP请求工具)
  • lxml(解析网页结构工具)
  • beautifulsoup(网页文档解析工具)

pip是Python的包管理工具,可以安装,升级,卸载Python包,并且只需要一条命令就行,是个非常棒的工具。
命令行输入命令开始下载:
pip3 install jupyter
pip3 install requests
pip3 install lxml
pip3 install bs4

jupyter简介

Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言。
Jupyter Notebook 的本质是一个 Web 应用程序,便于创建和共享文学化程序文档,支持实时代码,数学方程,可视化和markdown。 用途包括:数据清理和转换,数值模拟,统计建模,机器学习等等 。

requests简介

requests是个非常优秀,非常棒的库。使用它我们可以减少非常大的工作量,专注于对请求的创建和处理,而不需要去处理中间过程,诸如302跳转、cookie的发送与接收、表单的编码。
简单来说,我们就是使用它进行网络请求,获取到网页的内容。如果要自己全程实现一个请求的流程,代码会非常多。

lxml简介

lxml可以用来解析XML文件或者HTML文件,能够一个一个节点地解析,并且经过测试,lxml是Python所有解析HTML结构的包里面,解析速度最快的。lxml可以使用css选择器进行选择网页的节点,但是css选择器对新手不是很友好,所以我们采用了一个折中的办法,用beautifulsoup。

beautifulsoup简介

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间。

jupyter和requests的初步使用

jupyter的简单使用

打开命令提示符,输入命令jupyter notebook,接着浏览器会自动打开一个界面。
点击new按钮,新建一个文件,可以编写Python代码。

requests:HTTP for humans

import requests并发起一个请求
我们在jupyter的新的一个输入里面,键入下面的代码并点击运行:

1
2
3
4
import requests
response = requests.get("https://www.baidu.com")
print(response.status_code)
print(response.content)

输出结果为

1
2
3
200
b'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>\xe7\x99\xbe\xe5\xba\xa6\xe4\xb8\x80\xe4\xb8\x8b\xef\xbc\x8c\xe4\xbd\xa0\xe5\xb0\xb1\xe7\x9f\xa5\xe9\x81\x93</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw<span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off "bg s_btn_wr"><input type=submit id=su
autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=\xe7\x99\xbe> </div> </div> <div id=u1> <a href=htt\xe5\xba\xa6\xe4\xb8\x80\xe4\xb8\x8b class="bg s_btn" autofocus></span> </form> </div> </div> <do123.com name=tj_trhao123 class=mnav>haiv id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>\xe6\x96\xb0\xe9\x97\xbb</a> <ref=http://v.baidu.com name=tj_trvideoa href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.cov>\xe8\xb4\xb4\xe5\x90\xa7</a> <noscripm name=tj_trmap class=mnav>\xe5\x9c\xb0\xe5\x9b\xbe</a> <a href=http://v.baidu.com name=tj_trvidm%2f%3fbdorz_come%3d1 name=tj_login claeo class=mnav>\xe8\xa7\x86\xe9\xa2\x91</a> <a href=http://tieba.baidu.com name=tj_trtieba class=u.com/bdorz/login.gif?login&tpl=mn&u=\'mnav>\xe8\xb4\xb4\xe5\x90\xa7</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&ome=1")+ \'" name="tj_login" class="lb"amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>\xe7\x99\e=tj_briicon class=bri style="display:xbb\xe5\xbd\x95</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/log <div id=ftConw> <p id=lh> <a href=httpin.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "om>About Baidu</a> </p> <p id=cp>&copy;" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">\xe7\x99\xbb\xe5\xbd\x95</a>\');\xba\xa6\xe5\x89\x8d\xe5\xbf\x85\xe8\xa\r\n </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="disx8f\x8d\xe9\xa6\x88</a>&nbsp;\xe4\xba\xplay: block;">\xe6\x9b\xb4\xe5\xa4\x9a\xe4\xba\xa7\xe5\x93\x81</a> </div> </div> </div> <div id=> </div> </body> </html>\r\n'ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>\xe5\x85\xb3\xe4\xba\x8e\xe7\x99\xbe\xe5\xba\xa6</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>\xe4\xbd\xbf\xe7\x94\xa8\xe7\x99\xbe\xe5\xba\xa6\xe5\x89\x8d\xe5\xbf\x85\xe8\xaf\xbb</a>&nbsp;<a href=http://jianyi.baidu.com/class=cp-feedback>\xe6\x84\x8f\xe8\xa7\x81\xe5\x8f\x8d\xe9\xa6\x88</a>&nbsp;\xe4\xba\xacICP\xe8\xaf\x81030173\xe5\x8f\xb7&nbsp;<img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>\r\n'

第一行的200,使我们这个请求HTTP状态码,200表示请求成功。
第二行输出我们获取到的百度首页的HTML代码的二进制字符串,b’xxxxx’表示这个字符串是二进制的。我们只需要对响应的content(二进制)进行一次家吗,常见的解码方式有gbkutf-8。 requests.get():向目标网站发起一个get请求,请求的结果为response对象。 于是我们在输出二进制响应后面加上.docode(‘utf-8’)`,把二进制字符转换成字符串。
resquests发起一个请求就是这么简单。要发起post请求,也同样简单:

1
2
3
4
import requests
form = {'username': 'admin','password': 'admin123456'}
response = requests.post("https://www.baidu.com", data=form)
print(response.content.decode('utf-8'))

post请求我们一般用于对网页发送数据,比如登录、发送图片、文件等等。如果请求方式弄错了,很可能得不到正确的响应。

requests.session的使用

这里要介绍一下cookie:
Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。
Cookie相当于一个令牌,你拿着它去访问网站,网站就能辨别你是谁了。所以如果你登录了,你去访问其他需要登录的网页,都可以直接访问,因为浏览器在你访问的时候,默认会带上cookie。Cookie的添加、删除、更新是在服务器返回的响应里获取到的。
requests.get()是发送请求常用的一个办法。它不能做到的是对cookie的持久化:上一个请求获取到的cookie,没办法简单地传递到下一个请求去,这样两个requests.get()请求之间没有办法产生联系。如果是对于需要登录的网站来说,这是毁灭性的,我们会一直卡在登录界面。
下面要引入的就是requests的session。它能够自动管理cookie,也能够进行cookie的持久化。用法也很简单:

1
2
3
4
import requests
http_session = requests.session()
reponse = http_session.get(“https://www.baidu/com”)
print(reponse.content.decode(“utf-8”))

我们定义了一个http_session用来作为我们的session。然后我们使用这个http_session发出的每个请求,都会自动带上cookie;也会自动处理网站服务器返回的对cookie的操作。
这些过程对我们不可见,而我们只需要使用就好了。

把从浏览器获取到cookie添加到session里来绕过登录

首先补充一下cookie的知识:

  • 原因:http请求是无状态的,也就是说,你的每一次请求,网站服务器都会认识是一次新的请求。
  • 问题:既然每一次请求都是新的请求,那么网站识别用户就遇到困难了:一个网站需要服务于多个用户,每个用户的需要呈现的内容可能是不同的。如果每次请求都是全新的,服务器会不知道是谁发过来的,进而就可能造成一个混乱的局面,把A的消息发给了B,C的邮件给了A等等。
  • 解决方案:服务器如果需要识别你的身份,那它就给你发送一个或多个cookie(如果不需要对你进行特异性识别,那就没必要设置cookie了),之后你的每个请求默认会带上服务器设置的cookie(浏览器自动处理)。由于服务器给每个用户的分配的cookie的值是不同的,那服务器就可以轻松地通过cookie的值来识别用户了。
  • 拓展:既然服务器是通过cookie这个令牌识别你是谁的,那么只要你的请求带上了任意一个人的cookie去访问服务器,那么服务器就会认为你就是那个人。所以在以前有中间人攻击这个事情,黑客就是通过拦截你的请求,找到你的cookie,自己伪装成你,然后帮他发广告或者是进行一些其他的危险操作以获得利润。

如果我们需要爬取一个需要登录的网站,但是他的登录流程非常麻烦,甚至需要输入验证码。我们有没有什么比较轻便的办法来解决这个问题呢?
当然有:我们在浏览器上登录了,然后把浏览器上的网站发送给你的cookie,按照格式添加到我们的session里面,那么我们就无需登录,成功伪装成了浏览器里面的自己的账号了,进而可以直接进行爬取了(每个请求带上cookie,服务器就会认为我们是已经登录过了)。

怎么获取浏览器的cookie呢?
F12打开调试模式,然后选中NetWork(网络)。接着鼠标点到网页上去,按F5刷新界面。我们马上可以看到在调试窗口里面的列表有一个接一个的请求出现了,我们找到第一个请求(通常是第一个,具体请看请求的网址),点击一下,就显示出了这个请求的具体信息了。
接着再找到Request Header里面的Cookie。

  • 接着我们把所有的cookie复制下来。
  • 每一条cookie是以;隔开的,所以我们先以;把这些cookies分开,分割为一条条的cookie。
  • 对于每条cookie我们再以第一个=把一条cookie分为 name 和 value 两个部分。
  • 然后我们把这些key-value的数据,添加到一个dict里面
  • 最后把cookie添加到 http_session 的cookies里面。

BeautifulSoup解析豆瓣即将上映的电影信息

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。

本次以爬取豆瓣电影作为案例讲解BeautifulSoup的用法,我们需要爬取的内容有:所有影片的名字、详情链接、上映时间、影片类型、地区、关注者数量。

1、打开一个代码文件。
2、requests请求到网页源代码。
我们先进行爬取第一步,获取到网页源代码。
我们要爬取的网页的地址是:https://movie.douban.com/cinema/later/taiyuan/
那么我们开始编写代码来获取到这个网页的源代码:

1
2
3
4
import requests
url = “https://movie.douban.com/cinema/later/taiyuan/”
response = requests.get(url)
print(response.content.decode(utf-8))

在输出结果中,我们可以看到网页的源代码了,说明下载没有问题,而且在网页代码中,可以找到我们需要的电影信息。
3、保存网页到本地,方便快速加载
把网页保存到本地,这样我们可以用最短的时间加载到网页,而不用每次调试都去豆瓣请求一下。

1
2
3
4
5
6
7
8
9
10
import requests
url = "https://movie.douban.com/cinema/later/chengdu/"
response = requests.get(url)print(response.content.decode('utf-8'))# 保存网页到本地
file_obj = open('dianying.html', 'w')
# 以写模式打开名叫 dianying.html的文件
# 如果打开网页显示的是乱码那么就用下一行代码# file_obj = open('dianying.html', 'w', encoding="utf-8")
# 以写模式打开名叫 dianying.html的文件,指定编码为utf-8
file_obj.write(response.content.decode('utf-8'))
# 把响应的html内容
file_obj.close() # 关闭文件,结束写入

4、读取文件并用BeautifulSoup加载
我们开始键入代码读取文件并加载到BeautifulSoup里面:

1
2
3
4
5
6
7
8
9
10
11
12
from bs4 import BeautifulSoup  
# 从bs4引入BeautifulSoup# 读取文件内容到html变量里面
file_obj = open('dianying.html', 'r')
# 以读方式打开文件名为dianying.html的文件
html = file_obj.read()
# 把文件的内容全部读取出来并赋值给html变量
file_obj.close()
# 关闭文件对象

soup = BeautifulSoup(html, 'lxml')
# 初始化BeautifulSoupprint(soup)
# 输出BeautifulSoup转换后的内容

第一个参数html是网页的源代码,可以是个Unicode字符串,也可以是一个二进制字符串(如果第一个参数是字符串并且网页自带了charset信息,BS会默认采用网页的默认编码解码,否则默认以你当前文件执行的编码(通常是utf-8)进行解析。如果是二进制字符串,如果自己手动指定了编码,就以指定编码解析,否则默认utf-8解析)。
第二个参数lxml是BeautifulSoup采用的网页解析器,我们安装lxml用处就在这体现出来了。如果不指定,那么默认会采用Python内置的html.parser进行解析。
5、BeautifulSoup的基本使用语法规则

  • .find() 使用示例
    soup.find(‘a’)。那么会返回在soup包含的源代码中,遇到的第一个标签内容对象。
    soup.find(‘a’, id=’next’)。那么会返回在soup包含的源代码中,遇到的第一个有属性为id,值为next的对象,比如。(不只可以用id,大部分其他的属性都可以直接使用,比如src、name。 值得注意的是,class这个属性因为是Python关键字,不能直接使用,所以在BS里面,使用class_=’…’进行代替 )
    find返回的结果,依然可以继续使用find()或者find_all()方法。如果找不到指定的内容,find会返回None。

  • .find_all()使用示例
    soup.find_all(‘a’)。那么会返回在soup包含的源代码中,遇到的所有标签内容的可迭代对象(我们可以把它看成一个 list 或者数组)。
    soup.find_all(‘a’, class_=’next’)。那么会返回在soup包含的源代码中,遇到的所有属性为class,值为next的的 可迭代对象,比如。(语法和find也一样,class也不能直接写)
    find_all返回的“list”中的单个对象 依然可以继续使用find()或者find_all()方法。如果找不到指定的内容,find_all会返回一个空的“list”。

  • 获取元素的某个属性
    soup['src'],这样我们就能取出soup对象的src属性了。如果该属性不存在,那么程序会报错。

  • 获取元素中的所有文本
    soup.text,假设soup对象为<div>你好<a>复联</a></div>,那么这个操作返回字符串是你好复联

6、制订网页,制订提取策略
我们返回浏览器打开的豆瓣网页。找到网页中的第一个电影的名字,鼠标指向该名字,点击右键,选择 检查/审查元素,然后便会打开一个新的小窗口在页面上,并且将网页代码中电影的名字显示在了里面,并且你鼠标指向的元素会显示出它的大小,内容会被选中。
我们同时滑动鼠标的位置,应该会发现
当鼠标划到图片中的<ul>...</ul>标签的时候,复仇者联盟影片的详细信息被选中了。
当鼠标划到下一个<div class="item mod odd">...</div>的时候,下一个影片战犬瑞克斯的所有信息被选中了。
当鼠标划到图片上方的<div id="showing-soon" class="tab-bd">的时候,整个我们需要采集的影片信息都被选中了。

这告诉我们:
①.我们需要的内容在<div id="showing-soon" class="tab-bd"></div>里面。
②.每个影片的信息,都在一个<div class="item mod odd">...</div>或者<div class="item mod">...</div>里面。

所以我们先找到包括了所有影片的<div>,然后再从每个<div>中解析出我们需要的名字、链接等信息。
7、提取信息
接下来我们要做的就是在这个<div>中提取出我们需要的信息。
我们的目标是:

电影属性 文档中的位置
名字 在第2个<a>标签里面
链接 在第1个和第2个<a>标签的 href 属性里面
上映日期 在第1个<li>标签里面
类型 在第2个<li>标签里面
地区 在第3个<li>标签里面
关注者数量 在第4个<li>标签里面

名字:先获取所有的<a>标签,取第二个<a>标签的text属性。
链接:获取第一个或第二个<a>标签的href属性。
上映日期等信息:依次获取每个<li>标签的text属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from bs4 import BeautifulSoup  # 从bs4引入BeautifulSoup# 读取文件内容到html变量里面
file_obj = open('dianying.html', 'r') # 以读方式打开文件名为dianying.html的文件
html = file_obj.read() # 把文件的内容全部读取出来并赋值给html变量
file_obj.close() # 关闭文件对象

soup = BeautifulSoup(html, 'lxml') # 初始化BeautifulSoup# 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') # 找到所有的a标签
all_li_tag = each_movie.find_all('li') # 找到所有的li标签
movie_name = all_a_tag[1].text # 从第二个a标签的文字内容提取影片名字
moive_href = all_a_tag[1]['href'] # 从第二个a标签的文字内容提取影片链接
movie_date = all_li_tag[0].text # 从第1个li标签的文字内容提取影片上映时间
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))

8、合并请求网页代码和解析网页的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requestsfrom 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的内容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))

用HTML文件和csv文件保存爬取到的数据

我们拿到数据后,下一步就是将我们获取到的数据保存起来。这样才能够给后续的操作提供便利。
一般我们可以选用多种载体,根据成本、数据用途我们采用不同的方式存储数据。
主要的数据保存方法

  • 写到文本中,如txt、csv、excel等…
  • 保存到数据库,本地的sqlite、MySQL等…

保存数据库的操作需要了解数据库相关知识。

1、Python打开文件操作详解

  • 使用file_obj = open(“file_name”, ‘mode’, encoding=”encoding”)的方法进行操作。
  • file_name是你需要读取或者写入的文件路径及文件名(如”../data/ok.txt”是相对路径打开,如果只写一个”ok.txt”,那么就会默认保存到当前.py文件或者.ipynb文件的相同文件夹里面)

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

  • encoding在前面的章节说过了,是我们对文件进行操作所遵循的编码,默认为当前运行环境编码。Windows的默认编码是gbk,linux系统基本上是utf-8。不同的文件可以有不同的编码,设置读取的编码错误要么会报错,要么就得不到正确的内容。
  • file_obj是一个文件对象(Python里面也是万物皆对象,所以不要愁没有对象了),之后我们读取、写入数据都通过这个对象进行操作。

3、Python读取文件方法

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

4、Python写入文件的方法

  • file_obj.write(anystr),该方法接受一个字符串,并将字符串写入。
  • file_obj.writelines(list_of_str),该方法接受一个内部全是字符串的list数组,并将所有字符串一行一个写入(自动添加换行符)。
    5、关闭文件
  • file_obj.close() 关闭文件对象。打开了一个文件之后要记得关闭,否则可能会出现不可控的问题。但是如果用with方法打开了文件,则不需要手动关闭文件,在with语句块运行结束后,会自动关闭文件。

把文件保存到HTML文件

只要我们重复生成<tbody>标签里面的<tr>...<tr>中间的内容,并把我们的数据填进去,数据就会一行一行地被填充到表格中了。<tbody>前后的代码我们就只需要复制过来写入就好了。

所以我们就拿着之前的代码开始操作了:
注:python 里面三个”围起来的字符会被看做是一整个字符串,避免了换行符的麻烦。
.format()这个方法的用法是把字符串里面的{}字符,按次序一一替换成 format() 接受的所有参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import requestsfrom 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的内容

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!")

数据保存到csv文件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import csv
import requests
from bs4 import BeautifulSoup # 从bs4引入BeautifulSoup

# 请求网页
url = "https://movie.douban.com/cinema/later/taiyuan/"
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="utf-8", 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!")
支持一下
扫码关注我的微信公众号-大前端合集
  • 微信公众号-大前端合集