48行代码实现Python3爬取豆瓣电影排行榜
代码基于python3
,用到的类库有:
requests
:通过伪造请求头或设置代理等方式获取页面内容,参考文档
BeautifulSoup
:对页面进行解析,提取数据,参考文档
PyMySQL
:python3
版本中用于操作MySQL
数据库,python2
中则使用mysqldb
,Github
pip安装用到的几个类库:
1 2 3
| pip install requests pip install bs4 pip install pymysql
|
分析豆瓣电影页面
页面分析:
爬取数据之前,我们都需要对页面进行分析,看我们可以从中提取到哪些数据,从下图我们看到豆瓣电影top250的页面结构,我们可以从中提取出排行榜(rank)、电影名字(name)、电影详情页链接(link)、电影海报(poster)、电影评分(score)、电影评论(quote)
等,我在图中进行了标注
URL分析:
通过点击分页我们可以发现URL的格式为:https://movie.douban.com/top250?start=num&filter=
其中num
表示25
的倍数的数字,最小是0
也就是第一页,最大为225
也就是最后一页,这可以作为我们爬取页面的限制条件,filter
为过滤条件这里可不用管
代码
引入类库:
1 2 3
| import pymysql import requests from bs4 import BeautifulSoup
|
定义爬取链接,%d
用作数字占位:
1
| baseUrl = "https://movie.douban.com/top250?start=%d&filter="
|
定义爬取数据方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def get_movies(start): url = baseUrl % start # 拼接爬取链接 lists = [] # 存储此页面的电影数据 html = requests.get(url) # requests请求页面内容,由于豆瓣没有限制爬取,所以不用设置伪请求头 soup = BeautifulSoup(html.content, "html.parser") # BeautifulSoup解析页面内容 items = soup.find("ol", "grid_view").find_all("li") # 获取所有的电影内容 for i in items: movie = {} # 临时存取电影的数据 movie["rank"] = i.find("em").text # 电影排行榜 movie["link"] = i.find("div","pic").find("a").get("href") # 电影详情页链接 movie["poster"] = i.find("div","pic").find("a").find('img').get("src") # 电影海报地址 movie["name"] = i.find("span", "title").text # 电影名字 movie["score"] = i.find("span", "rating_num").text # 电影评分 movie["quote"] = i.find("span", "inq").text if(i.find("span", "inq")) else "" # 某些电影没有点评,没有就设为空 lists.append(movie) # 保存到返回数组中 return lists
|
连接数据库并创建数据表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 连接数据库,需指定charset否则可能会报错 db = pymysql.connect(host="localhost",user="root",password="root",db="test",charset="utf8mb4") cursor = db.cursor() # 创建一个游标对象 cursor.execute("DROP TABLE IF EXISTS movies") # 如果表存在则删除 # 创建表sql语句 createTab = """CREATE TABLE movies( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) NOT NULL, rank VARCHAR(4) NOT NULL, link VARCHAR(50) NOT NULL, poster VARCHAR(100) NOT NULL, score VARCHAR(4) NOT NULL, quote VARCHAR(50) )""" cursor.execute(createTab) # 执行创建数据表操作 ...... db.close() # 关闭数据库
|
将提取到的数据存储到数据表中:
1 2 3 4 5 6 7 8 9 10 11
| lists = get_movies(start) # 获取提取到数据 for i in lists: # 插入数据到数据库sql语句,%s用作字符串占位 sql = "INSERT INTO `movies`(`name`,`rank`,`link`,`poster`,`score`,`quote`) VALUES(%s,%s,%s,%s,%s,%s)" try: cursor.execute(sql, (i["name"], i["rank"], i["link"], i["poster"], i["score"], i["quote"])) db.commit() print(i[0]+" is success") except: db.rollback() start += 25
|
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import pymysql import requests from bs4 import BeautifulSoup baseUrl = "https://movie.douban.com/top250?start=%d&filter=" def get_movies(start): url = baseUrl % start lists = [] html = requests.get(url) soup = BeautifulSoup(html.content, "html.parser") items = soup.find("ol", "grid_view").find_all("li") for i in items: movie = {} movie["rank"] = i.find("em").text movie["link"] = i.find("div","pic").find("a").get("href") movie["poster"] = i.find("div","pic").find("a").find('img').get("src") movie["name"] = i.find("span", "title").text movie["score"] = i.find("span", "rating_num").text movie["quote"] = i.find("span", "inq").text if(i.find("span", "inq")) else "" lists.append(movie) return lists if __name__ == "__main__": db = pymysql.connect(host="localhost",user="root",password="root",db="test",charset="utf8mb4") cursor = db.cursor() cursor.execute("DROP TABLE IF EXISTS movies") createTab = """CREATE TABLE movies( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) NOT NULL, rank VARCHAR(4) NOT NULL, link VARCHAR(50) NOT NULL, poster VARCHAR(100) NOT NULL, score VARCHAR(4) NOT NULL, quote VARCHAR(50) )""" cursor.execute(createTab) start = 0 while (start < 250): lists = get_movies(start) for i in lists: sql = "INSERT INTO `movies`(`name`,`rank`,`link`,`poster`,`score`,`quote`) VALUES(%s,%s,%s,%s,%s,%s)" try: cursor.execute(sql, (i["name"], i["rank"], i["link"], i["poster"], i["score"], i["quote"])) db.commit() print(i["name"]+" is success") except: db.rollback() start += 25 db.close()
|