豆瓣电影爬取遇到的问题–状态码418
使用requests库的get方法获取豆瓣电影的响应,结果返回的是None,打印状态码一看是418,一般以4开头的HTTP状态码都是请求错误:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
RFC2324中出现:
任何尝试用茶壶冲泡咖啡的尝试都将导致错误代码“ 418我是茶壶”。生成的实体主体可能短而结实。
这听起来有些奇怪。
418 I’m a teapot: 这个响应状态码是在1998年定义的,是传统的IETF愚人节笑话之一。
一个笑话。。。
这应该是服务器的反爬虫措施,检测到爬虫就返回一个418.
要知道搜索引擎本质上也是一个爬虫,而我们在做的只是低配版的而已,浏览器里通过开发者模式可以看到有用户代理,头等信息,那么我们也使用requests库来添加用户代理来尝试一下。
解决418
# 豆瓣电影爬取
url = 'https://movie.douban.com/top250'
# 用于模拟http头的User-agent
user_list = (
{'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv2.0.1) Gecko/20100101 Firefox/4.0.1"},
{'user-agent': "Mozilla/5.0 (Windows NT 6.1; rv2.0.1) Gecko/20100101 Firefox/4.0.1"},
{'user-agent': "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11"},
{'user-agent': "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11"},
{'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"}
)
user_agent = random.choice(user_list)
response = requests.get(url, headers=user_agent)
构造用户代理元组,每次使用随即数选取一个代理,在get方法中填入用户代理。
random.choice()解析:
Choose a random element from a non-empty sequence.
从非空序列中选取一个随机元素。
打印看下结果(部分):
print(response.status_code)
print(response.text)
200
<!DOCTYPE html>
<html lang="zh-cmn-Hans" class="ua-mac ua-webkit">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="renderer" content="webkit">
<meta name="referrer" content="always">
<meta name="google-site-verification" content="ok0wCgT20tBBgo9_zat2iAcimtN4Ftf5ccsh092Xeyw" />
问题解决了。
正文开始,爬取豆瓣电影
我们需要使用bs4和requests库,没有的直接装一下:
pip install -U bs4 -i "https://pypi.doubanio.com/simple/"
pip install -U requests -i "https://pypi.doubanio.com/simple/"
用的源是豆瓣的,下载速度比较快。
代码,python3.7测试可以了:
"""
:copyright: (c) 2020 by 人生苦短.
"""
import sys
from bs4 import BeautifulSoup
import requests
import random
import re
import xlsxwriter
# 豆瓣电影爬取
# 获取http响应
def get_url(url):
# 用于模拟http头的User-agent
user_list = (
{'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv2.0.1) Gecko/20100101 Firefox/4.0.1"},
{'user-agent': "Mozilla/5.0 (Windows NT 6.1; rv2.0.1) Gecko/20100101 Firefox/4.0.1"},
{'user-agent': "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11"},
{'user-agent': "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11"},
{'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"}
)
user_agent = random.choice(user_list) # 随机选择一个代理
response = requests.get(url, headers=user_agent) # get()方法请求响应
return response.text
# 获取每页的数据
def get_data(html):
data, page_data = [], []
# 获取 1-电影详情链接 2-图片链接 3-影片中文名 4-影片外国名 5-评分 6-评价数 7-概况 8-相关信息
soup = BeautifulSoup(html, 'html.parser')
for item in soup.select('ol li'):
item = str(item)
soup_sub = BeautifulSoup(item, 'html.parser')
links = soup_sub.select('div div.pic a')[0]['href'] # 1-电影详情链接
data.append(links)
pictures = soup_sub.select('div div.pic a img')[0]['src'] # 2-图片链接
data.append(pictures)
names = soup_sub.find_all('span', class_='title') # 3-4 电影名
if 2 == len(names):
cname = names[0].string # 3-中文名
ename = names[1].string.replace('/', '').lstrip() # 4-英文名
else:
cname = names[0].string
ename = ''
data.append(cname)
data.append(ename)
scores = soup_sub.select('div div.bd div span.rating_num')[0].string # 5-评分
data.append(scores)
judges = soup_sub.find_all('span', string=re.compile(r'(\d*)人评价'))[0].string # 6-评价数
judges = judges.replace("人评价", "")
data.append(judges)
contents = soup_sub.select('span.inq')[0].string # 7-概况
data.append(contents)
infos = soup_sub.find_all('p', attrs={'class': ""})[0].get_text() # 8-相关信息
infos = infos.replace('\n', '').replace(' ', '')
data.append(infos)
page_data.append(data[:])
data.clear()
return page_data
# 保存数据
def save_data(all_data):
col, row = 0, 0
with xlsxwriter.Workbook('top250.xlsx') as workbook:
bold = workbook.add_format({'bold': True})
worksheet = workbook.add_worksheet('movie')
col_name = ('电影详情链接', '图片链接', '影片中文名', '影片外国名', '评分', '评价数', '概况', '相关信息')
worksheet.write_row('A1', col_name, bold)
for data in all_data:
for page_data in data:
row += 1
worksheet.write_row(row, col, page_data)
# 获取所有页的数据
def traverse_page(url):
print('正在下载到EXCEL文件里...')
data = []
sub_url = ''
while True:
html = get_url(url)
soup = BeautifulSoup(html, 'html.parser')
data.append(get_data(html))
print('len =', len(data))
try:
sub_url = soup.select('span.next a').pop()['href']
if sub_url:
url = 'https://movie.douban.com/top250' + sub_url
continue
else:
break
except IndexError:
save_data(data)
print('下载完成')
return
def main():
url = 'https://movie.douban.com/top250'
html = get_url(url)
traverse_page(url)
if __name__ == '__main__':
main()