您的位置:首页 > 编程语言 > Python开发

python爬虫之通过正则表达式获取豆瓣最新上映电影的海报

2019-07-09 01:50 453 查看

0.目录

1.分析页面
2.初步代码
3.代码解释
4.完整代码
5.提高海报质量
6.总结
7.更改后的完整代码

1.分析页面

上两次我们讲了xpath和beautifulsoup获取豆瓣最新上映电影的海报,这一次会使用正则表达式来获取。
xpath获取
BeautifulSoup获取

同样的,干活先看源代码

2.初步代码

这次我们同样是利用< img >标签下的src和alt获得我们想要的信息。

# encoding: utf-8

import requests
import re
from urllib import request

def get_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'Referer': 'https://movie.douban.com/',
}
response = requests.get(url, headers)
return response.text

def get_img(url):
text = get_page(url)

# 获取标签<div class="mod-bd">下的所有数据
lis = re.findall(r' <div class="mod-bd">(.*?)</div>', text, re.DOTALL)[0]
# 获取src和img
urls_img = re.findall(r'<li class="poster">.*?<img.*?src="(.*?)".*?/>', lis, re.DOTALL)
names = re.findall(r'<li class="poster">.*?<img.*?alt="(.*?)".*?/>', lis, re.DOTALL)
for url_img in urls_img:
print(url_img)
for name in names:
print(name)

def main():
url = 'https://movie.douban.com/cinema/nowplaying/guangzhou/'
get_img(url)

if __name__ == '__main__':
main()

展示运行结果的一部分:

3.代码解释

这次使用了标签< div class=“mod-bd” >和< /div >来限制范围,其实我们还可以使用其他的标签。比如< ul class=“lists” >和< /ul >,< div id=“nowplaying” >和< div id=“upcoming” >。唯一要注意的是,正则所做的只是匹配文本,没有所谓的标签范围的匹配。比如之前xpath使用的< div id=“nowplaying” >和< /div >,是因为在HTML里< div >标签开始,必然有< /div >与之对应,而xpath是会对应这一级标签的。但在正则里是不认识这些标签的,而是文本。所以,如果你使用< div id=“nowplaying” >和< /div >,你也只会匹配到下面的内容,即使< div class=“mod-bd” >和< /div >并不处于同一级。

<div id="nowplaying">
<div class="mod-hd">
<h2>正在上映</h2>
</div>

4.完整代码

# encoding: utf-8

import requests
import re
from urllib import request

def get_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'Referer': 'https://movie.douban.com/',
}
response = requests.get(url, headers)
return response.text

def get_img(url):
text = get_page(url)

# 获取标签<div class="mod-bd">下的所有数据
lis = re.findall(r' <div class="mod-bd">(.*?)</div>', text, re.DOTALL)[0]
# 获取src和img
urls_img = re.findall(r'<li class="poster">.*?<img.*?src="(.*?)".*?/>', lis, re.DOTALL)
names = re.findall(r'<li class="poster">.*?<img.*?alt="(.*?)".*?/>', lis, re.DOTALL)

fns_num = 1
num = len(urls_img)

for i in range(num):

# 下载剧照
request.urlretrieve(urls_img[i], 'images/' + names[i] + '.jpg')

# 显示剧照下载的进度
print("\r完成进度: {:.2f}%".format(fns_num * 100 / num), end="")
fns_num += 1

def main():
url = 'https://movie.douban.com/cinema/nowplaying/guangzhou/'
get_img(url)

if __name__ == '__main__':
main()

5.提高海报质量

我们通过src所给的url下载的海报仅仅是270x382的图片,不够清晰,作为画质党,我们是有追求的。点进一部电影的介绍页面,然后点击它的海报,再点击下面的查看原图。

会发现这是个1020x1428的图片,这才是我们需要的海报。我们对比一下这两个url。

https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2561172733.webp
https://img3.doubanio.com/view/photo/raw/public/p2561172733.jpg

也就是说我们只需要将之前获得的url里的s_ratio_poster更换成raw就可以获得高质量的海报了。

for i in range(num):
key = r'(?<=photo/).+?(?=/public)'
new_urls_img = re.sub(key, "raw", urls_img[i])
print(new_urls_img)
# 下载剧照
request.urlretrieve(new_urls_img, 'images/' + names[i] + '.jpg')

展示运行结果的一部分:

我们竟然发现程序报错了。点击链接,会发现我们能够打开url,然后刷新一下,会发现竟然变成了403,并且跟我们说没有访问此服务器上URL的权限。


我们查看正常打开的源代码和刷新后的源代码,会发现一个的状态是304,能够访问,一个是403,无法访问。再往下看request headers,会发现正常打开的headers里有referer,并且
https://movie.douban.com/photos/photo/2561172733/
这是我们上一个页面的url,这表明我们在访问原图的url时,服务器会检测你从哪个页面打开这个url的。也就是说,我们想要下载原图,就必须在get的时候添加拥有referer的headers。


从上图,我们可以发现referer中的数字id与之前获得的海报url的数字id相同,也就是豆瓣的电影id与该电影的显示海报的id是绑定的,那我们只需要将之前的url里提取id即可。

def urlretrieve(url, filename=None, reporthook=None, data=None):

之前使用的request.urlretrieve下载方式无法提交headers,也就是说我们需要更换下载方式。

for i in range(num):
key = r'(?<=photo/).+?(?=/public)'
new_urls_img = re.sub(key, "raw", urls_img[i])

# 下载剧照
id = re.findall(r'.*?/public/p(.*?).jpg', urls_img[i], re.DOTALL)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'referer': 'https://movie.douban.com/photos/photo/' + str(id) + '/'
}
r = requests.get(new_urls_img, headers=headers)
path = 'D://images//' + names[i] + '.jpg'
with open(path, 'wb') as f:
f.write(r.content)

展示运行结果的一部分:

6.总结

正则表达式是通过匹配文本来获取信息的,这使得我们在匹配某信息的同时,为了保证信息的准确性还需要添加一个合适的范围。在提高获取的海报的质量时,遇到了各种各样的问题,碰到问题时需要一个个的去克服。比如在下载图片时遇到了豆瓣的一个不算反爬的反爬,可以通过添加referer到headers再去访问就可以顺利解决。python的下载方式是有很多的,针对不同的需求可以使用不同的下载方式。

7.更改后的完整代码

# encoding: utf-8

import requests
import re

def get_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'Referer': 'https://movie.douban.com/',
}
response = requests.get(url, headers)
return response.text

def get_img(url):
text = get_page(url)

# 获取标签<div class="mod-bd">下的所有数据
lis = re.findall(r' <div class="mod-bd">(.*?)</div>', text, re.DOTALL)[0]
# 获取src和img
urls_img = re.findall(r'<li class="poster">.*?<img.*?src="(.*?)".*?/>', lis, re.DOTALL)
names = re.findall(r'<li class="poster">.*?<img.*?alt="(.*?)".*?/>', lis, re.DOTALL)

fns_num = 1
num = len(urls_img)

for i in range(num):
key = r'(?<=photo/).+?(?=/public)'
new_urls_img = re.sub(key, "raw", urls_img[i])

# 下载剧照
id = re.findall(r'.*?/public/p(.*?).jpg', urls_img[i], re.DOTALL)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'referer': 'https://movie.douban.com/photos/photo/' + str(id) + '/'
}
r = requests.get(new_urls_img, headers=headers)
path = 'D://images//' + names[i] + '.jpg'
with open(path, 'wb') as f:
f.write(r.content)
# 显示剧照下载的进度
print("\r完成进度: {:.2f}%".format(fns_num * 100 / num), end="")
fns_num += 1

def main():
url = 'https://movie.douban.com/cinema/nowplaying/guangzhou/'
get_img(url)

if __name__ == '__main__':
main()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐