1. 写在前面 1.1 说明 近来笔者在浅尝python网络爬虫,这是笔者写的第一个爬虫程序,仅仅是一步步按参考书的教程写成。写这篇博客仅为备忘用,没有什么技术含量,如果能对你有所帮助,那也再好不过。
我们以爬取酷狗歌曲TOP500 为例,获取网页上显示的TOP500的歌曲名、歌手、歌曲时长,并将结果输出到一个Excel表格中。
1.2 环境与准备
2. HTML爬取 第一步就是直接步入主题,用程序请求网站获取网页html文件。我们要做的事情就是:
加入请求头来伪装成浏览器
向目标网站发送http请求
获取服务器响应的html文件
应用“让HTTP服务人类”的Requests库,我们能够用一行代码实现这些操作。
1 2 3 4 5 import requests headers = { 'User-Agent' : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" } wb_data = requests.get('https://www.kugou.com/yy/rank/home/1-8888.html' ,headers=headers)
其中,请求头可以从chrome浏览器的 开发者工具 > 网络 中查询。如此我们便获得了酷狗TOP500第一页的html文档,可以用print(wb_data.text)
查看其内容。
有些网站具备反爬机制,这时print出来的结果可能是缺斤少两、奇奇怪怪的,这时就需要爬虫与反爬虫进行更高级的智斗了。所幸酷狗网页并没有反爬机制,我们可以很愉快地获取网页内容。
插一句,如果要爬取国外的网站,得先保证网络能够使浏览器正常访问网站,没有vpn的话可能会报错。
3. HTML解析 但是,我们得到的html文档内容太复杂了,真是看得人头大,我们怎样才能从这些奇怪的标记中找到我们需要的信息呢?
这时就该BeautifulSoup库派上用场啦,它可以对HTML/XML文档进行解析,将网页源代码解析为Soup文档,以便过滤提取数据。
1 2 from bs4 import BeautifulSoup soup = BeautifulSoup(wb_data.text,'html.parser' )
这时再进行print(soup.prettify())
可以看到解析后的Soup文档,看上去与原来的html文档没什么不同,但通过BeautifulSoup解析得到的Soup文档按章标准缩进格式的结构输出,为结构化数据的过滤提取做好准备。
4. 数据提取 终于到最重要的数据提取了。我们需要的数据到底在哪里?我们怎样把它们提取出来?
这里以提取“歌曲名称”为例,用chrome浏览器开发者工具中的“检查元素”功能,我们可以找到歌曲名称属标签在html文档的位置。鼠标右击标签,选择复制selector,这就是“歌曲名称”所属标签在html中的定位(好像也是用CSS制作样式时的定位方式)。
注意:将li:nth-child(1)
中的伪类删去,即改为li
,以获得整个页面22个歌曲名称。
接着我们就可以用BeautifulSoup中的select()
方法找到“歌曲名称”在Soup文档中的位置,用get_text()
方法获取title属性中的文本(也可以用get()
方法获取其他属性值),再进行字符串处理,就可以得到“歌曲名称”。
1 2 3 4 5 6 titles = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > a' )for title in titles: data = { 'song' :title.get_text(strip=True ).split('-' )[0 ] }print (data)
注:这里发现,在html中,title属性值为“歌手-歌曲名称”,但在使用方法get_text()
后,提取出内容为“歌曲名称-歌手”。目前不清楚原因,之后可能要去翻阅下官方文档。
5. 导入Excel 最后我们将提取到的数据导入到Excel表格中。这里只需要用到openpyxl库,就能够轻松实现工作簿编辑。
1 2 3 4 5 6 7 8 from openpyxl import Workbook workbook = Workbook() sheet = workbook.active row = 0 for title in titles: row += 1 sheet['A' +str (row)].value = title.get_text(strip=True ).split('-' )[0 ] workbook.save('songs_TOP500.xlsx' )
运行后发现当前目录下出现一个名为“songs_TOP500.xlsx”的xlsx文件,工作表中A列记录了歌曲名称。
6. 最终代码与运行结果 6.1 在最终代码前 基本工作已经完成,现在只需注意两点:
TOP500在23个网页html上,需根据url特点构造url列表,爬取这23个页面;
每次爬取网页需暂停0.5~1s,防止请求过快,触发网站的反爬程序
6.2 最终代码(仅供参考) 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 49 50 51 52 53 54 55 56 57 58 import requestsfrom bs4 import BeautifulSoupfrom openpyxl import Workbookimport time headers = { 'User-Agent' : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0Safari/537.36" } workbook = Workbook() sheet = workbook.active columns = ['A' ,'B' ,'C' ,'D' ] row = 0 def get_info (url ): wb_data = requests.get(url, headers=headers) soup = BeautifulSoup(wb_data.text, 'html.parser' ) ranks = soup.select('#rankWrap > div.pc_temp_songlist > ul > li > span.pc_temp_num' ) titles = 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' ) for rank, title, time in zip (ranks, titles, times): data1 = rank.get_text().strip() data2 = title.get_text(strip=True ).split('-' )[1 ] data3 = title.get_text(strip=True ).split('-' )[0 ] data4 = time.get_text().strip() listemp = [data1,data2,data3,data4] data = { 'rank' : data1, 'singer' : data2, 'song' : data3, 'time' : data4 } print (data) global row row += 1 for col, temp in zip (columns, listemp): sheet[col+str (row)].value = tempif __name__ == '__main__' : urls = ['https://www.kugou.com/yy/rank/home/{}-8888.html' .format (str (i)) for i in range (1 , 24 )] for url in urls: get_info(url) time.sleep(0.5 ) workbook.save('songs_TOP500.xlsx' )
6.3 运行结果
7. 参考文献 [1]罗攀,蒋仟.《从零开始学python网络爬虫》.机械工业出版社.2017:1-44
[2]Python 爬虫并且将数据写入Excel
[3]openpyxl库官方文档