爬虫实战 - 爬取豆瓣top250

  1 from bs4 import BeautifulSoup
  2 import urllib.request
  3 import urllib.parse
  4 import urllib.error
  5 import xlwt
  6 import re
  7 
  8 
  9 # Excel文件保存路径
 10 save_path = '豆瓣Top250.xls'
 11 
 12 # headers数据包
 13 head_package = {}
 14 head_package[
 15     'User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
 16 # head_package['Cookie'] = 'll="118226"; bid=Qfmj76DkrD8; __utmv=30149280.20459; douban-profile-remind=1; gr_user_id=a58b8c23-ff09-4e14-91d7-599fd84a9682; _vwo_uuid_v2=D007BD5CC7E89E79A31FD5B37908B75EB|9cfed6ff673a9ef600e186fcb321944d; douban-fav-remind=1; viewed="3671502"; _vwo_uuid_v2=D007BD5CC7E89E79A31FD5B37908B75EB|9cfed6ff673a9ef600e186fcb321944d; ap_v=0,6.0; __utmc=30149280; __utmz=30149280.1618040804.22.19.utmcsr=douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utmc=223695111; __utmz=223695111.1618040804.3.3.utmcsr=douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; __utma=30149280.756924018.1591256763.1618040804.1618043277.23; __utmb=30149280.0.10.1618043277; __utma=223695111.748862546.1609985591.1618040804.1618043277.4; __utmb=223695111.0.10.1618043277; _pk_ref.100001.4cf6=["","",1618043277,"https://www.douban.com/"]; _pk_ses.100001.4cf6=*; _pk_id.100001.4cf6=73809205b31654d3.1609985591.4.1618043308.1618041207.'
 17 
 18 # 正则表达式 - 规则 - 模板 字符串之前记得写 r
 19 # 链接
 20 re_link = re.compile(r'<a href="(.*?)">')  # 正则表达式中,()表示一个组-整体,该表达式是任意字符重复大于等于0次,并且有0或1个这样的字符串
 21 
 22 # 图片
 23 re_img = re.compile(r'<img .*src="(.*?)"', re.S)  # 忽略换行符
 24 
 25 # 片名
 26 re_title = re.compile(r'<span class="title">(.*)</span>')
 27 
 28 # 评分
 29 re_rating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
 30 
 31 # 评分人数
 32 re_people = re.compile(r'<span>(\d*人评价)</span>')  # 注意反斜杠 \d
 33 
 34 # 一句话
 35 re_quote = re.compile(r'<span class="inq">(.*)</span>')
 36 
 37 # 影片简介
 38 re_background = re.compile(r'<p class="">(.*?)</p>', re.S)  # 这里的 ?必须要加,原因见笔记
 39 
 40 
 41 def ask_url(para_url, para_head):
 42     request = urllib.request.Request(url=para_url, headers=para_head)
 43     para_html = ''  # response对象被 read后是二进制数据
 44     try:
 45         response = urllib.request.urlopen(request)
 46         para_html = response.read()
 47     except urllib.error as e:
 48         print(e.reason)
 49 
 50     return para_html
 51 
 52 
 53 def save_data(para_datalist, para_savepath):
 54     my_workbook = xlwt.Workbook(encoding='utf-8', style_compression=0)  # workbook对象
 55     my_sheet1 = my_workbook.add_sheet('sheet1', cell_overwrite_ok=True)  # 工作表;cell_overwrite_ok表示是否以新内容覆盖单元格内原有的内容
 56     first_row = ('影片链接', '图片链接', '中文名', '外国名', '影片评分', '评分人数', '一句话评价', '影片简介')  # 写入Excel的第一行标题
 57     for i in range(0, 8):
 58         my_sheet1.write(0, i, first_row[i])
 59 
 60     # 写入爬取的250条内容
 61     count_movie = 0  # 计数:第几个电影
 62     for i in range(0, 250):
 63         # 每条中有8种信息
 64         for j in range(0, 8):
 65             my_sheet1.write(i+1, j, para_datalist[count_movie+j])
 66 
 67         print('正在爬取第%d条电影' % (i+1))
 68         count_movie += 8  # 切换到下一部电影
 69 
 70     # 保存Excel文件
 71     my_workbook.save(para_savepath)
 72     print('爬取完成!')
 73 
 74 
 75 def get_data(para_url, para_head):
 76     datalist = []
 77 
 78     # 顺序爬取豆瓣电影top250的10个网页
 79     for i in range(0, 10):
 80         temp = 'start=' + str(i * 25)
 81         pre_url = para_url.replace('start=0', temp)
 82         temp_html = ask_url(pre_url, para_head).decode('utf-8')
 83 
 84         # 爬取完成后对数据(temp_html)进行解析
 85         soup = BeautifulSoup(temp_html, 'html.parser')
 86         # find_all的新方法,标签名与类名同时查找(笔记中的 *kwargs)
 87         # 找到了所有的 item 标签,并将标签及其内容返回到了 temp
 88         for temp in soup.find_all('div', class_='item'):
 89             # print(type(temp))  # 在 bs4中找到的标签等均是bs4的文件类型:bs4.element.Tag
 90             # 所以在下面的正则查找时要转换成 string 类型才可以
 91             str_temp = str(temp)
 92 
 93             # 链接
 94             temp_link = re.findall(re_link, str_temp)[0]  # 有可能在一个item中找到多个,我们只打印一个
 95             datalist.append(temp_link)
 96             # findall最后只返回组内元素 - 连接
 97 
 98             # 图片
 99             temp_img = re.findall(re_img, str_temp)[0]
100             datalist.append(temp_img)
101 
102             # 名称 - 注意其中包含中文名与外国名两个元素
103             temp_title = re.findall(re_title, str_temp)
104             if len(temp_title) == 2:
105                 datalist.append(temp_title[0])  # 中文名
106                 datalist.append(temp_title[1].replace('/', '').strip())  # 英文名, 并且把英文名前的斜杠消除
107             else:
108                 datalist.append(temp_title[0])
109                 datalist.append(' ')  # 若没有英文名,则必须置为空,保证顺序
110 
111             # 评分
112             temp_score = re.findall(re_rating, str_temp)
113             datalist.append(temp_score[0])
114 
115             # 评分人数
116             temp_people = re.findall(re_people, str_temp)[0]
117             datalist.append(temp_people)
118 
119             # 一句话
120             temp_quote = re.findall(re_quote, str_temp)
121             if temp_quote:
122                 datalist.append(temp_quote[0].replace('', ''))
123             else:
124                 datalist.append(' ')
125 
126             # 简介
127             temp_background = re.findall(re_background, str_temp)[0]
128             # 去掉<br/>
129             temp_background = re.sub(r'<br(\s+)?/>(\s+)?', '', temp_background)  # \s匹配空格、空白、tab
130             # 去掉 /
131             temp_background = re.sub(r'/', ' ', temp_background)
132             # 去掉两个及以上的不间断空白符 \xa0或空格
133             temp_background = re.sub('(\xa0| )+', ' ', temp_background)
134             datalist.append(temp_background.strip())  # strip函数去掉开头结尾的换行符和空格
135     print(datalist)  # 测试 datalist
136     return datalist
137 
138 
139 natural_url = 'http://movie.douban.com/top250?start=0&filter='
140 douban_dataList = get_data(natural_url, head_package)
141 save_data(douban_dataList, save_path)

 记得认真看注释!

最终结果:

 

posted @ 2021-04-17 10:30  vosoland  阅读(129)  评论(0)    收藏  举报