有了上次利用python爬虫抓取糗事百科的经验,这次自己动手写了个爬虫抓取豆瓣电影Top250的简要信息。
1.观察url
首先观察一下网址的结构 http://movie.douban.com/top250?start=0&filter=&type= :
可以看到,问号?后有三个参数 start、filter、type,其中start代表页码,每页展示25部电影,0代表第一页,以此类推25代表第二页,50代表第三页...
filter顾名思义,是过滤已经看过的电影,filter和type在这里不重要,可以不管。
2.查看网页源代码
打开上面的网址,查看源代码,可以看到信息的展示结构如下:
1 <ol class="grid_view"> 2 <li> 3 <div class="item"> 4 <div class="pic"> 5 <em class="">1</em> 6 <a href="http://movie.douban.com/subject/1292052/"> 7 <img alt="肖申克的救赎" src="http://img3.douban.com/view/movie_poster_cover/ipst/public/p480747492.jpg" class=""> 8 </a> 9 </div> 10 <div class="info"> 11 <div class="hd"> 12 <a href="http://movie.douban.com/subject/1292052/" class=""> 13 <span class="title">肖申克的救赎</span> 14 <span class="title"> / The Shawshank Redemption</span> 15 <span class="other"> / 月黑高飞(港) / 刺激1995(台)</span> 16 </a> 17 18 19 <span class="playable">[可播放]</span> 20 </div> 21 <div class="bd"> 22 <p class=""> 23 导演: 弗兰克·德拉邦特 Frank Darabont 主演: 蒂姆·罗宾斯 Tim Robbins /...<br> 24 1994 / 美国 / 犯罪 剧情 25 </p> 26 27 28 <div class="star"> 29 <span class="rating5-t"><em>9.6</em></span> 30 <span>646374人评价</span> 31 </div> 32 33 <p class="quote"> 34 <span class="inq">希望让人自由。</span> 35 </p> 36 </div> 37 </div> 38 </div> 39 </li>
其中<em class="">1</em>代表排名,<span class="title">肖申克的救赎</span>代表电影名,其他信息的含义也很容易能看出来。
于是接下来可以写正则表达式:
1 pattern = re.compile(u\'<div.*?class="item">.*?<div.*?class="pic">.*?\' 2 + u\'<em.*?class="">(.*?)</em>.*?\' 3 + u\'<div.*?class="info">.*?<span.*?class="title">(.*?)\' 4 + u\'</span>.*?<span.*?class="title">(.*?)</span>.*?\' 5 + u\'<span.*?class="other">(.*?)</span>.*?</a>.*?\' 6 + u\'<div.*?class="bd">.*?<p.*?class="">.*?\' 7 + u\'导演: (.*?) \' 8 + u\'主演: (.*?)<br>\' 9 + u\'(.*?) / (.*?) / \' 10 + u\'(.*?)</p>\' 11 + u\'.*?<div.*?class="star">.*?<em>(.*?)</em>\' 12 + u\'.*?<span>(.*?)人评价</span>.*?<p.*?class="quote">.*?\' 13 + u\'<span.*?class="inq">(.*?)</span>.*?</p>\', re.S)
在此处flag参数re.S代表多行匹配。
3.使用面向对象的设计模式编码
代码如下:
1 # -*- coding:utf-8 -*- 2 __author__ = \'Jz\' 3 import urllib2 4 import re 5 import sys 6 7 class MovieTop250: 8 def __init__(self): 9 #设置默认编码格式为utf-8 10 reload(sys) 11 sys.setdefaultencoding(\'utf-8\') 12 self.start = 0 13 self.param = \'&filter=&type=\' 14 self.headers = {\'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; WOW64)\'} 15 self.movieList = [] 16 self.filePath = \'D:/coding_file/python_file/File/DoubanTop250.txt\' 17 18 def getPage(self): 19 try: 20 URL = \'http://movie.douban.com/top250?start=\' + str(self.start) 21 request = urllib2.Request(url = URL, headers = self.headers) 22 response = urllib2.urlopen(request) 23 page = response.read().decode(\'utf-8\') 24 pageNum = (self.start + 25)/25 25 print \'正在抓取第\' + str(pageNum) + \'页数据...\' 26 self.start += 25 27 return page 28 except urllib2.URLError, e: 29 if hasattr(e, \'reason\'): 30 print \'抓取失败,具体原因:\', e.reason 31 32 def getMovie(self): 33 pattern = re.compile(u\'<div.*?class="item">.*?<div.*?class="pic">.*?\' 34 + u\'<em.*?class="">(.*?)</em>.*?\' 35 + u\'<div.*?class="info">.*?<span.*?class="title">(.*?)\' 36 + u\'</span>.*?<span.*?class="title">(.*?)</span>.*?\' 37 + u\'<span.*?class="other">(.*?)</span>.*?</a>.*?\' 38 + u\'<div.*?class="bd">.*?<p.*?class="">.*?\' 39 + u\'导演: (.*?) \' 40 + u\'主演: (.*?)<br>\' 41 + u\'(.*?) / (.*?) / \' 42 + u\'(.*?)</p>\' 43 + u\'.*?<div.*?class="star">.*?<em>(.*?)</em>\' 44 + u\'.*?<span>(.*?)人评价</span>.*?<p.*?class="quote">.*?\' 45 + u\'<span.*?class="inq">(.*?)</span>.*?</p>\', re.S) 46 while self.start <= 225: 47 page = self.getPage() 48 movies = re.findall(pattern, page) 49 for movie in movies: 50 self.movieList.append([movie[0], movie[1], movie[2].lstrip(\' / \'), 51 movie[3].lstrip(\' / \'), movie[4], 52 movie[5], movie[6].lstrip(), movie[7], movie[8].rstrip(), 53 movie[9], movie[10], movie[11]]) 54 55 def writeTxt(self): 56 fileTop250 = open(self.filePath, \'w\') 57 try: 58 for movie in self.movieList: 59 fileTop250.write(\'电影排名:\' + movie[0] + \'\r\n\') 60 fileTop250.write(\'电影名称:\' + movie[1] + \'\r\n\') 61 fileTop250.write(\'外文名称:\' + movie[2] + \'\r\n\') 62 fileTop250.write(\'电影别名:\' + movie[3] + \'\r\n\') 63 fileTop250.write(\'导演姓名:\' + movie[4] + \'\r\n\') 64 fileTop250.write(\'参与主演:\' + movie[5] + \'\r\n\') 65 fileTop250.write(\'上映年份:\' + movie[6] + \'\r\n\') 66 fileTop250.write(\'制作国家/地区:\' + movie[7] + \'\r\n\') 67 fileTop250.write(\'电影类别:\' + movie[8] + \'\r\n\') 68 fileTop250.write(\'电影评分:\' + movie[9] + \'\r\n\') 69 fileTop250.write(\'参评人数:\' + movie[10] + \'\r\n\') 70 fileTop250.write(\'简短影评:\' + movie[11] + \'\r\n\r\n\') 71 print \'文件写入成功...\' 72 finally: 73 fileTop250.close() 74 75 def main(self): 76 print \'正在从豆瓣电影Top250抓取数据...\' 77 self.getMovie() 78 self.writeTxt() 79 print \'抓取完毕...\' 80 81 DouBanSpider = MovieTop250() 82 DouBanSpider.main()
代码比较简单,最后将信息写入一个文件,没有什么需要解释的地方。
4.运行截图
5.问题说明
打开文件浏览时发现有个别电影没有抓取下来或者信息中出现html代码,后来排查发现是因为豆瓣有部分电影的信息不全,缺少主演等导致html代码出现差异而导致正则表达式没有匹配到或者匹配出错。