爬虫简单一之获取酷狗top500名歌曲的名字,作者,排名,时间。并存入txt,csv,mysql。
准备使用环境为Python3.6+csv+time+requests+beautifulsoup+os+pymysql
环境说明 安装所要使用的库,使用库的说明
-
csv库来实现存储csv文件
-
time设置爬取间隔
-
request访问URL
-
beautifulsoup解析页面
-
os来创建文件夹来保存文件
-
pymysql来连接mysql数据库,把数据存储到mysql中
1.准备URL
打开https://www.kugou.com/yy/rank/home/1-8888.html?from=rank只能显示前22名
从图中看出的是只显示前22名,需要更多内容要下载客户端,但是通过改变1-8888.html中的数字1可以访问排行的前500名,一共需要24页。(他们后端可能并没有屏蔽其他的连接,仍然是可以访问的)
2.使用beautifulsoup的selector来获取所需要的具体内容,如歌手,歌名,歌曲时间等信息。(下面提供了一个简单而快捷的方法)
2.1右击要选取的元素内容,点击检查可以看到具体的源代码中的具体位置
2.2再右击要选取的元素,选中copy会出现很多选项,常用的有copy selector和copy xpath,copy selector是使用beautifulsoup中的selector方法来选取元素时要使用的,而copy xpath是使用lxml库时使用xpath方法时使用的,使用这一个方法可以提高代码的生产效率。本文使用的是beautifulsoup的selector方法。
2.3下面是使用selector的具体代码(先使用beautiful soup来封装一下text再使用selector方法来选取。通过一下几行代码就可以把排名,名字,时间和歌手选取出来(歌手的名字和歌曲的名字在一个标签中使用-来分隔,选取出来之后可以使用split方法对字符串进行切分)。
html = requests.get(url, headers=headers)
soup = BeautifulSoup(html.text, 'lxml')
ranks = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > span.pc_temp_num')
names = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > a')
times = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > span.pc_temp_tips_r > span')
源代码中的使用-连接的歌曲名个歌手名
分隔分别选出来的歌手名字和歌曲名字
name = names[i].get_text().strip().split('-')[1]
signer = names[i].get_text().strip().split('-')[0]
3.当得到所有的信息之后,接下来就是要存储到文件当中,可以使用txt,csv,mysql等文件进行存储。
3.1存储到txt中(在存储到txt文件中时,使用的当写入时,只能写入一个元素,所以要把所有元素使用+号来连接起来再使用f.write()来存储到txt中去)
# 封装成函数
def write_txt(message):
with open('../tmp/_02_kugou/kuGou.txt', 'a+') as f:
f.write(message + '\n')
# 在进行调用时要使用加号把多个元素连接
write_txt(rank + name + signer + time1)
3.2存储到csv中首先open()函数打开当前路径下的名字为…/tmp/_02_kugou/kuGou.csv的文件,如果不存在这个文件,则创建它,返回f文件对象。csv.writer(f)返回writer对象csv_writer。writerow()方法是一行一行写入,writerows方法是一次写入多行。
def write_csv(rank, name, signer, time1):
with open('../tmp/_02_kugou/kuGou.csv', 'a+') as f:
csv_writer = csv.writer(f)
csv_writer.writerow([rank, name, signer, time1])
3.3存储到mysql中,使用pymysql的connect方法传入多个参数之后连接数据库,创建一个游标,使用游标来执行sql语句,把获取到的值存储到数据库中。
def writer_mysql(rank, name, signer, time1):
con = pymysql.connect(user='root', password='root', db='spider', host='localhost', port=3306, charset='utf8')
cursor = con.cursor()
try:
sql = '''INSERT INTO kugou(rank, name, signer, time) VALUES('%d', '%s', '%s', '%s')'''
cursor.execute(sql % (int(rank), name, signer, pymysql.escape_string(time1)))
con.commit()
except pymysql.err.IntegrityError:
pass
cursor.close()
con.close()
注意在向mysql存储数据的时候出现 pymysql.err.ProgrammingError: 1064 (Python字符串转义问题)时
使用模块MySQLdb自带的针对mysql的字符转义函数 escape_string把要存储的元素转义一下如
cursor.execute(sql % (int(rank), name, signer, pymysql.escape_string(time1)))
如果还是出现pymysql.err.ProgrammingError: 1064 错误就使用三引号’‘’ 来括取sql语句。应该就可以解决这个错误了
sql = '''INSERT INTO kugou(rank, name, signer, time) VALUES('%d', '%s', '%s', '%s')'''
cursor.execute(sql % (int(rank), name, signer, pymysql.escape_string(time1)))
4.定义一个main函数,迭代所有的要爬取的URL链接,给爬虫函数传入链接,运行爬虫,作为一个文明的人,最好爬虫一次使用time.sleep()休息一段时间,一是为了不给服务器造成很大的客流量,二是爬虫过快,封禁ip等因素导致爬虫失败。
if __name__ == '__main__':
urls = ['https://www.kugou.com/yy/rank/home/' + str(i) + '-8888.html' for i in range(1, 24)]
for url in urls:
print(url)
get_message(url)
time.sleep(5)
5.完整代码
import csv
import time
import requests
from bs4 import BeautifulSoup
import os
import pymysql
if not os.path.exists('../tmp/_02_kugou'):
os.makedirs('../tmp/_02_kugou')
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
}
def get_message(url):
html = requests.get(url, headers=headers)
soup = BeautifulSoup(html.text, 'lxml')
ranks = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > span.pc_temp_num')
names = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > a')
times = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > span.pc_temp_tips_r > span')
# print(len(ranks))
for i in range(0, len(ranks)):
rank = ranks[i].get_text().strip()
name = names[i].get_text().strip().split('-')[1]
signer = names[i].get_text().strip().split('-')[0]
time1 = times[i].get_text().strip()
write_txt(rank + name + signer + time1)
write_csv(rank, name, signer, time1)
writer_mysql(rank, name, signer, time1)
# print(rank, name, signer, time1)
def write_txt(message):
with open('../tmp/_02_kugou/kuGou.txt', 'a+') as f:
f.write(message + '\n')
def write_csv(rank, name, signer, time1):
with open('../tmp/_02_kugou/kuGou.csv', 'a+') as f:
csv_writer = csv.writer(f)
csv_writer.writerow([rank, name, signer, time1])
def writer_mysql(rank, name, signer, time1):
con = pymysql.connect(user='root', password='root', db='spider', host='localhost', port=3306, charset='utf8')
cursor = con.cursor()
try:
sql = '''INSERT INTO kugou(rank, name, signer, time) VALUES('%d', '%s', '%s', '%s')'''
cursor.execute(sql % (int(rank), name, signer, pymysql.escape_string(time1)))
con.commit()
except pymysql.err.IntegrityError:
pass
cursor.close()
con.close()
if __name__ == '__main__':
urls = ['https://www.kugou.com/yy/rank/home/' + str(i) + '-8888.html' for i in range(1, 24)]
for url in urls:
print(url)
get_message(url)
time.sleep(5)