之前我们介绍了几种爬虫常见的页面解析方式,今天我们就来看一下这些方式在实际情况下的用法,以后在抓取数据的时候可以选择合适自己的那种。
本文我们用“ 提取猫眼电影TOP100的电影名称、时间、评分、图片等信息“ 为例
1. 准备工作
首先准备环境,再次说一下我的环境:win7、Anconda3
本次需要的包是:requests、lxml、bs4
2. 请求页面
现在开始正式请求页面,获取页面信息:
页面地址:猫眼电影排行
看下图,我们需要的信息均可在这里提取出来:
将页面拖到最下面,可以看到翻页信息,这块我们之后再看。
下面开始撸码。
3. 代码
1.发送请求, 获取页面信息,顺便带上代码结构,下面只写相关的方法了:
import re
import requests
from lxml import etree
from bs4 import BeautifulSoup
class TopMovieSpider(object):
def __init__(self):
self._start_url = "https://maoyan.com/board/4"
self._headers = {
'Connection': 'keep-alive',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36',
}
def get_response(self):
response = requests.get(self._start_url, headers=self._headers)
if response.status_code == 200:
return response.content.decode('utf-8')
return None
def run(self):
# 1.发出请求,获取页面信息
req_result = self.get_response()
print(req_result)
if __name__ == '__main__':
tm_spider = TopMovieSpider()
tm_spider.run()
看下我们所需要的信息在哪:
注意:在这个地方提醒一下,我们在google中查看页面信息的时候,不要去看Elements下的页面信息,要去Network下找到相应的请求看Response返回的,下面会举例说明。
2. Xpath获取信息
因为作者比较习惯使用Xpath,所以首先使用Xpath详解信息获取的整个过程:
通过页面源码我们可以看到电影排行信息在class
为board-wrapper
的dl
标签中,在dl
标签下有若干dd
标签,每个dd
标签下包含了一部电影的信息,每个dd
标签下的结构都是相同的:
在这里我们做个对比:Element下的页面跟Network
下相应请求的Response返回的页面信息:可以发现两者在一些信息都有不同,如果以Element为准提取的话,会获取不到你所需要的信息,大家可以尝试一下。
dd
标签下共有三个标签,在这可以很明显的看到a
标签的title
属性就是电影的名称,展开a
标签就能发现,下面的img
标签就是电影的图片,a
标签上面有个i
标签,里面的内容是排名,所以我们可以这样写:
def xpath_parse(self, req_result):
"""
Xpath解析页面
:param req_result:
:return:
"""
html = etree.HTML(req_result)
# 排名
movie_index_list = html.xpath('//i[contains(@class, "board-index")]/text()')
# 电影名称: 我们可以根据 a 标签的class来确定,同样获取 a 标签中的 title 属性,就为电影名称
movie_name = html.xpath('//a[@class="image-link"]/@title')
print(movie_name)
# 电影图片: 我们这里不难发现,a 标签中的第二个 img 标签的 data-src 属性就是图片的地址, 可以用该图片的 class 属性来确定
movie_picture = html.xpath('//img[@class="board-img"]/@data-src')
print(movie_picture)
看下输出结果:
['霸王别姬', '肖申克的救赎', '罗马假日', '这个杀手不太冷', '泰坦尼克号', '唐伯虎点秋香', '乱世佳人', '魂断蓝桥', '辛德勒的名单', '天空之城']
['https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/289f98ceaa8a0ae737d3dc01cd05ab052213631.jpg@160w_220h_1e_1c', 'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@160w_220h_1e_1c', 'https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/58782fa5439c25d764713f711ebecd1e201941.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/b0d986a8bf89278afbb19f6abaef70f31206570.jpg@160w_220h_1e_1c', 'https://p1.meituan.net/movie/ba1ed511668402605ed369350ab779d6319397.jpg@160w_220h_1e_1c']
下一步我们再看一下剩余的信息:主演、上映时间跟评分
跟名称一样的分析方式,这里就不过多赘述,看代码:
# 电影主演: 我们可以根据 class 为 star 的 p 标签来确定,提取出来后做个简单的整理:去除空格
movie_star_list = html.xpath('//p[@class="star"]/text()')
movie_star_list = [movie_star.strip() for movie_star in movie_star_list]
print(movie_star_list)
# 上映时间:我们可以根据 class 为 releasetime 的 p 标签来确定, 有些还带着上映地区
show_time_list = html.xpath('//p[@class="releasetime"]/text()')
print(show_time_list)
# 电影评分:评分在页面上是有两部分组成的:小数,整数; 整数部分可以通过 class 为 integer 的 i 标签确定, 小数部分可以通过class为fraction的i标签确定,提取出来后做个简单的整理:相加
movie_grade_integer_list = html.xpath('//i[@class="integer"]/text()')
movie_grade_decimals_list = html.xpath('//i[@class="fraction"]/text()')
movie_grade_list = [movie_grade_integer_list[i] + movie_grade_decimals_list[i] for i in range(len(movie_grade_integer_list))]
print(movie_grade_list)
看下输出结果:
['主演:张国荣,张丰毅,巩俐', '主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', '主演:格利高里·派克,奥黛丽·赫本,埃迪·艾伯特', '主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼', '主演:莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩', '主演:周星驰,巩俐,郑佩佩', '主演:费雯·丽,克拉克·盖博,奥利维娅·德哈维兰', '主演:费雯·丽,罗伯特·泰勒,露塞尔·沃特森', '主演:连姆·尼森,拉尔夫·费因斯,本·金斯利', '主演:寺田农,鹫尾真知子,龟山助清']
['上映时间:1993-07-26', '上映时间:1994-09-10(加拿大)', '上映时间:1953-09-02(美国)', '上映时间:1994-09-14(法国)', '上映时间:1998-04-03', '上映时间:1993-07-01(中国香港)', '上映时间:1939-12-15(美国)', '上映时间:1940-05-17(美国)', '上映时间:1993-12-15(美国)', '上映时间:1992-05-01']
['9.5', '9.5', '9.1', '9.5', '9.5', '9.1', '9.1', '9.2', '9.2', '9.0']
到这里,我们第一页所有的上榜电影都已经获取到了,接下来我们来提取剩余的电影信息:
首先分析页面地址,从图中看到我们只能拿到一部分页面地址,中间位置的地址都被隐藏了,所以我们只能走别的路了,根据可见的地址,我们可以找到对应的规律:
我们从这很容易就能看出他的规律:第n页,offset的值是10 * (n -1),总共就10页,我们可以加个循环:
for i in range(10):
print('=' * 30 + f'第{i + 1}页')
movie_info_list = tm_spider.run(i * 10)
for movie_info in movie_info_list:
print(movie_info)
# 加个强制睡眠,以防反爬
time.sleep(10)
下面贴上完整代码,如有可以优化的地方欢迎大家指导:
import re
import requests
from lxml import etree
from bs4 import BeautifulSoup
import time
class TopMovieSpider(object):
def __init__(self):
self._start_url = "https://maoyan.com/board/4"
self._headers = {
'Connection': 'keep-alive',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36',
}
def get_response(self, offert_set):
response = requests.get(f'{self._start_url}?offset={offert_set}', headers=self._headers)
if response.status_code == 200:
return response.content.decode('utf-8')
return None
def run(self, offert_set):
# 1.发出请求,获取页面信息
req_result = self.get_response(offert_set)
# 2.解析页面,获取信息
## (1)、Xpath解析
movie_info_list = self.xpath_parse(req_result)
yield movie_info_list
def xpath_parse(self, req_result):
"""
Xpath解析页面
:param req_result:
:return:
"""
movie_info_list = []
html = etree.HTML(req_result)
# 排名
movie_index_list = html.xpath('//i[contains(@class, "board-index")]/text()')
# 电影名称: 我们可以根据 a 标签的class来确定,同样获取 a 标签中的 title 属性,就为电影名称
movie_name_list = html.xpath('//a[@class="image-link"]/@title')
# 电影图片: 我们这里不难发现,a 标签中的第二个 img 标签的 data-src 属性就是图片的地址, 可以用该图片的 class 属性来确定
movie_picture_list = html.xpath('//img[@class="board-img"]/@data-src')
# 电影主演: 我们可以根据 class 为 star 的 p 标签来确定,提取出来后做个简单的整理:去除空格
movie_star_list = html.xpath('//p[@class="star"]/text()')
movie_star_list = [movie_star.strip() for movie_star in movie_star_list]
# 上映时间:我们可以根据 class 为 releasetime 的 p 标签来确定, 有些还带着上映地区
show_time_list = html.xpath('//p[@class="releasetime"]/text()')
# 电影评分:评分在页面上是有两部分组成的:小数,整数; 整数部分可以通过 class 为 integer 的 i 标签确定, 小数部分可以通过class为fraction的i标签确定,提取出来后做个简单的整理:相加
movie_grade_integer_list = html.xpath('//i[@class="integer"]/text()')
movie_grade_decimals_list = html.xpath('//i[@class="fraction"]/text()')
movie_grade_list = [movie_grade_integer_list[i] + movie_grade_decimals_list[i] for i in range(len(movie_grade_integer_list))]
for i in range(len(movie_index_list)):
movie_info_dict = dict()
movie_info_dict['movie_index'] = movie_index_list[i]
movie_info_dict['movie_name'] = movie_name_list[i]
movie_info_dict['movie_picture'] = movie_picture_list[i]
movie_info_dict['movie_star'] = movie_star_list[i]
movie_info_dict['show_time'] = show_time_list[i]
movie_info_dict['movie_grade'] = movie_grade_list[i]
movie_info_list.append(movie_info_dict)
return movie_info_list
if __name__ == '__main__':
tm_spider = TopMovieSpider()
for i in range(10):
print('=' * 30 + f'第{i + 1}页')
movie_info_list = tm_spider.run(i * 10)
for movie_info in movie_info_list:
print(movie_info)
time.sleep(10)
结果的话就贴个图吧:
至于最后的保存,大家就可以随意了,我在这里就不赘述了。
3. 结语
这篇主要通过一个简单的数据采集来介绍的爬虫的基本流程,还有Xpath的简单用法,但也用的不是很多,详细的用法还需要大家自己去慢慢摸索了。下一篇会介绍一下其他几种解析的用法。