简介: 为什么爬取该网页? ● 比较懒,不想一页页地去翻100部电影的介绍,想在一个页面内进行总体浏览(比如在excel表格中);想深入了解一些比较有意思的信息,比如:哪部电影的评分最高?哪位演员的作品数量最多?哪个国家/地区上榜的电影数量最多?哪一年上榜的电影作品最多等。
1. 为什么爬取该网页?● 比较懒,不想一页页地去翻100部电影的介绍,想在一个页面内进行总体浏览(比如在excel表格中);
想深入了解一些比较有意思的信息,比如:哪部电影的评分最高?哪位演员的作品数量最多?哪个国家/地区上榜的电影数量最多?哪一年上榜的电影作品最多等。这些信息在网页上是不那么容易能直接获得的,所以需要爬虫。
2. 爬虫目标● 从网页中提取出top100电影的电影名称、封面图片、排名、评分、演员、上映国家/地区、评分等信息,并保存为csv文本文件。
● 根据爬取结果,进行简单的可视化分析。
平台:windows7 SublimeText3
3. 爬取步骤3.1. 网址URL分析
首先,打开猫眼Top100的url网址: maoyan/board/4?offset=0。页面非常简单,所包含的信息就是上述所说的爬虫目标。下拉页面到底部,点击第2页可以看到网址变为:maoyan/board/4?offset=10。因此,可以推断出url的变化规律:offset表示偏移,10代表一个页面的电影偏移数量,即:第一页电影是从0-10,第二页电影是从11-20。因此,获取全部100部电影,只需要构造出10个url,然后依次获取网页内容,再用不同的方法提取出所需内容就可以了。
下面,用requests方法获取第一个页面。
3.2. Requests获取首页数据
先定义一个获取单个页面的函数:get_one_page(),传入url参数。
1def get_one_page(url): 2 try: 3 headers = { 4 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/66.0.3359.181 Safari/537.36'} 5 # 不加headers爬不了 6 response = requests.get(url, headers=headers) 7 if response.status_code == 200: 8 return response.text 9 else: 10 return None 11 except RequestException: 12 return None 13 # try-except语句捕获异常
接下来在main()函数中设置url。
1def main(): 2 url = 'maoyan/board/4?offset=0' 3 html = get_one_page(url) 4 print(html) 5 6 7if __name__ == '__main__': 8 main()
运行上述程序后,首页的源代码就被爬取下来了。如下图所示:
接下来就需要从整个网页中提取出几项我们需要的内容,用到的方法就是上述所说的四种方法,下面分别进行说明。
3.3. 4种内容解析提取方法
3.3.1. 正则表达式提取
第一种是利用正则表达式提取。
什么是正则表达式? 下面这串看起来乱七八糟的符号就是正则表达式的语法。
1'<dd>.*?board-index.*?>(d )</i>.*?src="https://img.360qiwen.com(.*?)".*?name"><a.*?>(.*?)</a>.*?'
它是一种强大的字符串处理工具。之所以叫正则表达式,是因为它们可以识别正则字符串(regular string)。可以这么定义:“ 如果你给我的字符串符合规则,我就返回它”;“如果字符串不符合规则,我就忽略它”。通过requests抓取下来的网页是一堆大量的字符串,用它处理后便可提取出我们想要的内容。
如果还不了解它,可以参考下面的教程:
runoob/regexp/regexp-syntax.html
w3cschool/regexp/zoxa1pq7.html
下面,开始提取关键内容。右键网页-检查-Network选项,选中左边第一个文件然后定位到电影信息的相应位置,如下图:
可以看到每部电影的相关信息都在dd这个节点之中。所以就可以从该节点运用正则进行提取。
第1个要提取的内容是电影的排名。它位于class="board-index"的i节点内。不需要提取的内容用'.*?'替代,需要提取的数字排名用()括起来,()里面的数字表示为(d )。正则表达式可以写为:
1'<dd>.*?board-index.*?>(d )</i>'
接着,第2个需要提取的是封面图片,图片网址位于img节点的'src'属性中,正则表达式可写为:
1'src="https://img.360qiwen.com(.*?)".*?'
第1和第2个正则之间的代码是不需要的,用'.*?'替代,所以这两部分合起来写就是:
1'<dd>.*?board-index.*?>(d )</i>.*?src="https://img.360qiwen.com(.*?)"
同理,可以依次用正则写下主演、上映时间和评分等内容,完整的正则表达式如下:
1'<dd>.*?board-index.*?>(d )</i>.*?src="https://img.360qiwen.com(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>'
正则表达式写好以后,可以定义一个页面解析提取方法:parse_one_page(),用来提取内容:
1def parse_one_page(html): 2 pattern = repile( 3 '<dd>.*?board-index.*?>(d )</i>.*?src="https://img.360qiwen.com(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S) 4 # re.S表示匹配任意字符,如果不加,则无法匹配换行符 5 items = re.findall(pattern, html) 6 # print(items) 7 for item in items: 8 yield { 9 'index': item[0], 10 'thumb': get_thumb(item[1]), # 定义get_thumb()方法进一步处理网址 11 'name': item[2], 12 'star': item[3].strip()[3:], 13 # 'time': item[4].strip()[5:], 14 # 用两个方法分别提取time里的日期和地区 15 'time': get_release_time(item[4].strip()[5:]), 16 'area': get_release_area(item[4].strip()[5:]), 17 'score': item[5].strip() item[6].strip() 18 # 评分score由整数 小数两部分组成 19 }
Tips:
re.S:匹配任意字符,如果不加,则无法匹配换行符;
yield:使用yield的好处是作为生成器,可以遍历迭代,并且将数据整理形成字典,输出结果美观。具体用法可参考:blog.csdn/zhangpinghao/article/details/18716275;
.strip():用于去掉字符串中的空格。
上面程序为了便于提取内容,又定义了3个方法:get_thumb()、get_release_time()和 get_release_area():
1# 获取封面大图 2def get_thumb(url): 3 pattern = repile(r'(.*?)@.*?') 4 thumb = re.search(pattern, url) 5 return thumb.group(1) 6# p0ituan/movie/5420be40e3b755ffe04779b9b199e935256906.jpg@160w_220h_1e_1c 7# 去掉@160w_220h_1e_1c就是大图 8 9 10# 提取上映时间函数 11def get_release_time(data): 12 pattern = repile(r'(.*?)((|$)') 13 items = re.search(pattern, data) 14 if items is None: 15 return '未知' 16 return items.group(1) # 返回匹配到的第一个括号(.*?)中结果即时间 17 18 19# 提取国家/地区函数 20def get_release_area(data): 21 pattern = repile(r'.*((.*))') 22 # $表示匹配一行字符串的结尾,这里就是(.*?);(|$,表示匹配字符串含有(,或者只有(.*?) 23 items = re.search(pattern, data) 24 if items is None: 25 return '未知' 26 return items.group(1)
Tips:
'r':正则前面加上'r' 是为了告诉编译器这个string是个raw string,不要转意''。当一个字符串使用了正则表达式后,最好在前面加上'r';
'|' 正则'|'表示或','′:∗∗正则′∣′表示或′,′'表示匹配一行字符串的结尾;
.group(1):意思是返回search匹配的第一个括号中的结果,即(.*?),gropup()则返回所有结果2013-12-18(,group(1)返回'('。
接下来,修改main()函数来输出爬取的内容:
1def main(): 2 url = 'maoyan/board/4?offset=0' 3 html = get_one_page(url) 4 5 for item in parse_one_page(html): 6 print(item) 7 8 9if __name__ == '__main__': 10 main()
Tips:
if _ name_ == '_ main_':当.py文件被直接运行时,if _ name_ == '_ main_'之下的代码块将被运行;当.py文件以模块形式被导入时,if _ name_ == '_ main_'之下的代码块不被运行。
参考:blog.csdn/yjk13703623757/article/details/77918633。
运行程序,就可成功地提取出所需内容,结果如下:
1{'index': '1', 'thumb': 'p1ituan/movie/20803f59291c47e1e116c11963ce019e68711.jpg', 'name': '霸王别姬', 'star': '张国荣,张丰毅,巩俐', 'time': '1993-01-01', 'area': '中国香港', 'score': '9.6'} 2{'index': '2', 'thumb': 'p0ituan/movie/54617769d96807e4d81804284ffe2a27239007.jpg', 'name': '罗马假日', 'star': '格利高里·派克,奥黛丽·赫本,埃迪·艾伯特', 'time': '1953-09-02', 'area': '美国', 'score': '9.1'} 3{'index': '3', 'thumb': 'p0ituan/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg', 'name': '肖申克的救赎', 'star': '蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', 'time': '1994-10-14', 'area': '美国', 'score': '9.5'} 4{'index': '4', 'thumb': 'p0ituan/movie/e55ec5d18ccc83ba7db68caae54f165f95924.jpg', 'name': '这个杀手不太冷', 'star': '让·雷诺,加里·奥德曼,娜塔莉·波特曼', 'time': '1994-09-14', 'area': '法国', 'score': '9.5'} 5{'index': '5', 'thumb': 'p1ituan/movie/f5a924f362f050881f2b8f82e852747c118515.jpg', 'name': '教父', 'star': '马龙·白兰度,阿尔·帕西诺,詹姆斯·肯恩', 'time': '1972-03-24', 'area': '美国', 'score': '9.3'} 6 7... 8} 9[Finished in 1.9s]
以上是第1种提取方法,如果还不习惯正则表达式这种复杂的语法,可以试试下面的第2种方法。
点击了解更多,学习第2种方法
〖特别声明〗:本文内容仅供参考,不做权威认证,如若验证其真实性,请咨询相关权威专业人士。如有侵犯您的原创版权或者图片、等版权权利请告知 wzz#tom.com,我们将尽快删除相关内容。