手把手教你学爬虫


本文爬虫不涉及付费内容,所爬取数据都是公开的

1.request爬取静态加载数据

就拿爬取音乐歌单来举例吧,本人比较喜欢杨宗纬,就先爬取一下他的歌单吧。
首先是确定url,这个url就是你要爬的数据的地址。

url为https://music.163.com/artist?id=6066
url 确定之后就可以开始写爬虫了。

第一步,导入相关库

import requests
from lxml import html
from lxml import etree 
import urllib 
import re

第二步,写入url和请求头

写入headers,里面放入请求头是为了伪装成浏览器,如果不知道怎么来的可以自行百度,这里只教你怎么找到headers。
进入你想要爬取的url,按下F12打开开发者工具,点击Network,刷新一下页面,在Name里随便找一个点击,再找到Headers里面的Request Headers,里面的User-Agent参数就是我们要的headers。
在这里插入图片描述

url = 'https://music.163.com/artist?id=6066'
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"    
}

第三步,确定方法

现在已经有了url,headers,找到该页面的请求方法。
和上面一样,只不过最后是在这里。
在这里插入图片描述
很明显是GET方法,所以就用GET方法,编码用utf-8。

r = requests.get(url, headers=headers)
r.encoding = 'utf-8'

接下来就看看是否成功。

s = r.text
s

在这里插入图片描述
成功请求到了,接下来就是获得想要的数据了

第四步,获得数据

因为源码已经有了,现在唯一不确定的是我想要的歌单是否是动态加载。判断的方法很简单,第一个方法就是用xpath定位元素解析,查看数据是否存在。
首先你要学会xpath定位,如果不会的话可以到你想要的数据位置右键点击,到Copy,里面有选项为Copy Xpath,这种方法缺点就是只能定位一个元素,如果你想要爬取其他的就要自己写xpath定位。

我这里Xpath是//div[@class="ttc"]/span/a/b/@title
在这里插入图片描述

简单解释一下,/ 表示的是下一级标签,// 同理表示2级或多级,//div是我匹配div标签,但是div标签太多了,怎么能知道我要的是哪个呢,所以就用到了后面的class,因为我要的数据在b标签那里。
这时候写//div[@class="ttc"]//b/@title是一样的,我上面是为让你们能好好理解 / 的作用。
好,理解了上面的Xpath之后就来获取数据吧

html = etree.HTML(s)
html.xpath('//div[@class="ttc"]/span/a/b/@title')

在这里插入图片描述
结果是有数据,但是不是我们想要的数据,应该是被加密了,反爬虫的手段。
还记得上面判断是否为动态加载的数据方法吗,第二种方法就是按下CTRL+F,查找你要的数据,看看所需数据是否在你请求到的网页源码里
在这里插入图片描述
看来是静态加载的,但是在Xpath定位获取数据的时候可能被加密了,才会出现上面的情况。
这里就需要用到正则了,正则太香了。如果你不会正则的话,可以去百度自行学习,并不难,但是掌握了之后匹配字符串,提取或者清洗数据很方便。

names = re.findall(r'<ul class="f-hide">(.*?)</ul>',s)
names

在这里插入图片描述

names = re.findall(r"<a href=(.*?)>(.*?)</a>",str(names))
names

在这里插入图片描述
因为爬取下来的数据终归是要保存下来的,所以我们可以用上面的数据做三列,歌曲名称,歌曲地址,歌曲id

song_url_list = []
song_names = []
for i in names:
    split1 = i[0].split('"')[1]
    song_url_list.append('https://music.163.com/#'+split1)
    song_names.append(i[1])
song_url_list

在这里插入图片描述

song_id = [int(j) for i in names for j in re.findall(r'\"\/song\?id=(.*?)\"',i[0])]
song_id

在这里插入图片描述
获取歌手名字

t = re.findall(r'<textarea id="song-list-pre-data" style="display:none;">(.*?)</textarea>',s)
# t
#下面是正则匹配字符串次数,然后做相应次数的替换
#因为把他们变成json的时候报错,把false和null替换就好了
len(re.findall(r"false",str(t)))#250
t1 = str(t).replace("false","0",250)
len(re.findall(r"null",str(t)))#500
t2 = str(t1).replace("null","0",500)

import json
t3 = eval(t2[3:-3])
# t3
songer = []
for j in t3:
    k = [i["name"]for i in j['artists']]
    songer.append(k)
songer    

在这里插入图片描述
很明显,这样的数据是不允许储存到表里的,太难看,清洗一下

songer_true = []
for i in songer:
    k = re.sub(r"\[|\]",'',str(i))
    k = re.sub(r"\'",'',k)
    songer_true.append(k)

在这里插入图片描述

第五步,保存数据

album = [t3[i]['album']['name'] for i in range(50)]

import pandas as pd
df = pd.DataFrame()
df['演唱歌手'] = songer_true
df['歌曲名称'] = song_names
df['歌曲地址'] = song_url_list
df['歌曲专辑'] = album
df['歌曲id'] = song_id
df.to_csv('杨宗纬.csv',index=False)

在这里插入图片描述

2.Ajax爬取动态加载数据

第一步,找到数据所在url和相关参数

url的寻找方法在我写的2021电工杯数据建模B题的第三问的Ajax数据爬取
相关参数的位置同样在所找的url的Request Headers里,再加一个data,这个位置在Form Data里,值得注意的是,这里的请求方法变成了POST
在这里插入图片描述

import requests
Ajax_url = 'https://music.163.com/weapi/song/lyric?'
headers = {
    'origin':'https://music.163.com',
    'referer':'https://music.163.com/#/song?id=490602750',
    'sec-ch-ua-mobile': '?0',
    'sec-fetch-dest': 'empty',
    'sec-fetch-mode': 'cors',
    'sec-fetch-site': 'same-origin',
    
    'X-Requested-With':'XMLHttpRequest',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'
}
data={
    'csrf_token':'a050496bc510ce2bdaab667e33bb77f1',
    'params':'Z3bEY6b0ZvVu5EedFZHnGQaS0Vv/ZDJ4JOeV1ZvX3UIhk88p6BURTa2tPr08n+HRWDN3w9F4I5fX1sqbJVJQdk1m/MD9EBbB70RaiB1jJvtXiXIdG1YJtC7NFAt45Ar8EhtDvCcgIgAF13oN5QurLKQii4rZFXwcou6aiye5XaI9qZnD3KAF76M70Z6gVz73',
'encSecKey':'99cb31cca793ecb41e3d808dc8365e7ec92e9a5c20afb80e17b43e0e596b2a6a92480c93c515cf9da26d1b4ad53ce60a6ae8f5365435f6451a374caf50cfaa094f9d32ab04e24dd430dcbe0d32dd237d4e734a17a5ba8efe0536832c618732ad3d9f3cfb0d48d121ece0785bab6c8a78d3fc9a92f247df8edfb7b64595451226'
}

第二步,请求到数据,清洗,保存

请求

res = requests.post(url=Ajax_url,headers=headers,data=data)
res.text

在这里插入图片描述
清洗

import re
geci = re.findall(r'\](.*?)\\n',res.text)

在这里插入图片描述
保存

geci1 = pd.DataFrame()
geci1["越过山丘"] = geci
geci1.to_csv('《越过山丘》歌词.txt',index=False)

在这里插入图片描述

3.selenium爬取音乐评论

第一步,安装对应浏览器版本的驱动

首先需要你下载对应浏览器版本的驱动,我是谷歌浏览器,所以需要下载对应版本的chromedriver,查看浏览器版本在关于Chrome
在这里插入图片描述
下载chromedriver的地址
一定要对应版本,不然没法用,下载好了把他放在Python目录下的Scripts文件里,还有放在C:\Program Files\Google\Chrome\Application里,并配好环境变量。在这里插入图片描述

第二步,爬取数据

值得一提的是,这里有一个内嵌页面。webDriver只能在一个页面上对元素识别和定位,对于frame/iframe表单内嵌页面上的元素无法直接定位,此时就需要通过switch_to.frame()方法将当前定位的主题切换为iframe表单的内嵌页面中。
在这里插入图片描述

selenium就是模拟用户的操作来进行爬取数据的,所以定位,点击等操作需要好好去看一下,如果需要登录的话,还可以提前将要输入的账号,密码写好,到时候直接放进去。这里不多介绍,有需要的可以去官方文档查看,学习一个库的最好方法就是去他的官方文档学习。不多介绍不是因为懒或者什么,是因为太笼统了,太抽象。

import pandas as pd
import re
f = open('杨宗纬.csv','r',encoding='utf-8')
df = pd.read_csv(f)
df.head()

from selenium import webdriver 
import time
driver = webdriver.Chrome()
data= []#创建列表来储存数据
for url in df['歌曲地址']:
    driver.get(url)
    driver.switch_to.frame('g_iframe')#进入内嵌框架
    time.sleep(5)#停5秒
    for page in (range(3)):#这里是翻页的次数,每首歌爬取4页的评论
        selectors = driver.find_elements_by_xpath('//div[@class="cmmts j-flag"]/div')#定位
        try:
            for selector in selectors:
                text = selector.find_element_by_xpath('.//div[@class="cnt f-brk"]').text#评论者名字,评论内容等
                num = selector.find_element_by_xpath('.//div[@class="rp"]').text#时间,点赞数等
                data.append([url,text,num])


            next_button = driver.find_element_by_xpath('//a[starts-with(@class,"zbtn znxt js-n-")]')#定位下一页按钮
            driver.execute_script('arguments[0].click();', next_button)#点击
            time.sleep(5)
        except:
            pass
driver.quit()#退出

第三步,数据清洗,并保存

p = [i[2] for i in data]#时间,点赞数
text_list = [i[1] for i in data]#评论
p1 = [re.findall(r"\((.*?)\)",i) for i in p]
p2 = [i for i in p1]
p3 = [re.findall(r"\'(.*?)\'",str(i)) for i in p2]
p4 = []
for i in p3:
    try:
        p4.append(int(i[0]))
    except:
        p4.append(0)
        
df1 = pd.DataFrame()
df1['回复时间'] = [i.split('\n')[0] for i in p] 
df1['点赞数'] = p4
df1["用户id"] = [i.split(':')[0] for i in text_list]
df1['评论内容'] = [i.split(':')[1:] for i in text_list]
p2 = []
for i in range(len(df1['评论内容'])):
    p2.append(df1['评论内容'][i][0])
df1['评论内容'] = p2
df1['歌曲地址'] = [(i[0]) for i in data]  
song_id = []
for i in df1['歌曲地址']:
    k = re.findall(r"\d",i)
    k2 = ''
    n = 3
    while n<=len(k):
        try:
            k1 = k[n]
            k2 +=k1
            n +=1
        except:
            song_id.append(k2)
            break
df1["歌曲id"] = song_id
df1.drop_duplicates(subset=['评论内容'],keep='first',inplace=True)
df1.to_csv('歌曲评论.csv',index=False,encoding='utf-8-sig')      

在这里插入图片描述

  • 6
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼肝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值