最近在家看了些关于爬虫的资料,发一个小项目给想学爬虫的人带个路~尽可能地介绍一下每步的理由和做法。关于爬虫的资料太多了,初学者很容易迷失在各种各样的框架、库中(比如博主),也是借这个小项目给大家理一下爬虫的学习路程!
一般而言,其实爬虫就是三个步骤:(1)网页爬取(2)数据解析(3)数据存储
网页爬取: 获取你需要的网页的HTML代码(这部分需要注意一下反爬虫机制),常用的库有:urllib或者requests,二者选其一即可
数据解析: 从获取的HTML代码中得到自己想要的数据,常用的库:lxml(xpath语法)或者beautifulSoup4或者re(正则),三者最好都要学,初学者可以从beautifulSoup4开始学。在我看来,数据解析是整个爬虫的精华也是难点。
数据存储: 很容易理解,即把解析到的数据存储为自己想要的格式。
网页爬取
使用requests库
按下F12,进入开发者模式,选中Network,然后刷新,可以看到一个数据包,选中,查看其Headers。豆瓣的对爬虫很友好,我们的headers中只需要伪装两项:Referer和User-Agent,将浏览器中的复制下来即可!
import requests
#设置Headers值
headers = {
'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值
response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
f.write(text)
有一点需要说明,为什么是发送get请求,也是在NetWork-Headers中得知的,一般而言,常用的是get和post请求。
我们可以得到html.txt如下:
数据解析
使用lxml库
首先先对HTML代码分析,同样是在开发者模式下,定位到整个需要爬取的页面,可以看到在class = grid_view的<ol>下面有一串的<li>标签,每个<li>标签即为一个电影。
from lxml import etree
import requests
#设置Headers值
headers = {
'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值
response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movie = ul.xpath("./li")[0] #查找该ol标签下的li标签,这里取第一项
print(etree.tostring(movie, encoding='utf-8').decode('utf-8')) #打印li标签中的HTML代码
得到HTML代码如下:
<li>
<div class="item">
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img width="100" alt="肖申克的救赎" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" class="">
</a>
</div>
<div class="info">
<div class="hd">
<a href="https://movie.douban.com/subject/1292052/" class="">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港) / 刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
导演: 弗兰克·德拉邦特 Frank Darabont 主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
1994 / 美国 / 犯罪 剧情
</p>
<div class="star">
<span class="rating5-t"></span>
<span class="rating_num" property="v:average">9.7</span>
<span property="v:best" content="10.0"></span>
<span>1857327人评价</span>
</div>
<p class="quote">
<span class="inq">希望让人自由。</span>
</p>
</div>
</div>
</div>
</li>
<li>
继续分析,这里取三种数据为例
title:可以看到<img>标签的alt属性即为电影名
img:可以看到<img>标签的src属性即为图片地址
rating:可以看到class属性为star的<div>标签下的class属性为rating_num的<span>中的文字内容即为评分
from lxml import etree
import requests
#设置Headers值
headers = {
'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值
response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movie = ul.xpath("./li")[0] #查找该ol标签下的li标签,这里取第一项
title = movie.xpath(".//img/@alt")[0]
img = movie.xpath(".//img/@src")[0]
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0]
print("名称:", title, "\n图片: ", img, "\n评分:", rating)
运行结果
数据存储
电影的图片下载到文件夹,其他的数据存储到json文件中,这里还是用肖申克的救赎为例。
import json
from lxml import etree
import requests
#设置Headers值
headers = {
'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
'Referer': 'https://movie.douban.com/top250'
}
url = 'https://movie.douban.com/top250' #url值
response = requests.get(url, headers=headers) #使用requests库发送get请求
text = response.text #获取html代码
#存储得到的html代码
with open('./html.txt', 'w', encoding='utf-8') as f:
f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movie = ul.xpath("./li")[0] #查找该ol标签下的li标签,这里取第一项
title = movie.xpath(".//img/@alt")[0] #名称
img = movie.xpath(".//img/@src")[0] #图片url
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0] #评分
movieUrl = movie.xpath(".//a/@href")[0] #电影链接
quote = movie.xpath(".//span[@class='inq']/text()")[0] #语录
info = {"名称": title, "评分": rating, "链接": movieUrl, "语录": quote} #信息存储为字典
#信息保存到json文件
with open('movieTop250.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(info, ensure_ascii=False, indent=4, separators=(',', ':')))
#保存图片
with requests.get(img, stream=True, headers=headers) as resp:
with open('./img/1.jpg', 'wb') as fd:
for chunk in resp.iter_content():
fd.write(chunk)
完整代码
以上完成了肖申克的救赎的信息存储和图片存储,其他电影的同理,只需要增加一些循环即可。
另外我们爬取的https://movie.douban.com/top250只有25个电影,其他还有9个页面,点下一个页面的url为https://movie.douban.com/top250?start=25&filter=,可以发现规律,每次start递进25。
整理一下代码:
import requests
from lxml import etree
import json
#设置Headers值
headers = {
'User-Agent': "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/80.0.3987.116 Mobile Safari/537.36",
'Referer': 'https://movie.douban.com/top250'
}
cnt = 1
infos = []
for i in range(0, 250, 25):
url = 'https://movie.douban.com/top250?start='+str(i)+'&filter=' # url值
response = requests.get(url, headers=headers) #使用requests库发送post请求
text = response.text #获取html代码
#存储得到的html代码
# with open('./html.txt', 'w', encoding='utf-8') as f:
# f.write(text)
html = etree.HTML(text)
ul = html.xpath("//ol[@class='grid_view']")[0] #查找class为grid_view的ol标签,返回的是列表,所以取第0项去除列表
movies = ul.xpath("./li") #查找该ol标签下的li标签,这里取第一项
# print(etree.tostring(movies, encoding='utf-8').decode('utf-8')) #打印li标签中的HTML代码
for movie in movies:
title = movie.xpath(".//img/@alt")[0] #名称
img = movie.xpath(".//img/@src")[0] #图片url
rating = movie.xpath(".//div[@class='star']/span[@class='rating_num']/text()")[0] #评分
movieUrl = movie.xpath(".//a/@href")[0] #电影链接
quote = movie.xpath(".//span[@class='inq']/text()") #语录
quote = " " if not quote else quote[0]
info = {"名称": title, "排名": cnt, "评分": rating, "链接": movieUrl, "语录": quote} #信息存储为字典
infos.append(info)
#保存图片
with requests.get(img, stream=True, headers=headers) as resp:
with open('./img/'+str(cnt)+'.jpg', 'wb') as fd:
cnt += 1
for chunk in resp.iter_content():
fd.write(chunk)
#信息保存到json文件
with open('movieTop250.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(infos, ensure_ascii=False, indent=4, separators=(',', ':')))
结果截图: