实验内容:
本次实验爬取39问医生网中口腔科分类下的所有在线单轮问答记录,每页32条,共100页,总数据量为3200条,最终结果以excel格式保存。
开发环境:
Windows+Pycharm+Python3.9
Edge浏览器
requests库:命令行输入pip install requests
BeautifulSoup:命令行输入pip install beautifulsoup4
pandas:命令行输入pip install pandas
openpyxl:命令行输入pip install openpyxl
分析网站结构:
进入网站页面(口腔科每日最新提问和医生回复第1页_39问医生_39健康网),可以看到这是一个目录页,而要获取具体的问答内容则需要点击目录页中的超链接进行跳转。
此外,通过观察其网址我们可以发现,目录页的网址信息是与页码对应的(例如第1页就是xxx-1.html),而问答页的网址则没有什么规律(https://ask.39.net/question/_te7uy5.html),这就意味着我们需要先从目录页爬取所有问答页的URL,再借助该URL爬取我们所需要的问答记录。
目录页:
问答页:
获取User-Agent:
首先讲一下为什么要获取User-Agent。它的作用是将我们的爬虫伪装成一个用户正常的浏览器访问,否则网站就有可能会察觉到正在请求访问的是一个爬虫,从而拒绝访问。
按键盘F12进入开发者工具,或鼠标右击任一位置点击检查,即可看到网站的HTML代码,仔细观察可以发现HTML中的信息和网页中显示的内容是对应的,如图所示:
点击这里的”网络“:
之后刷新网页,可以看到下面多出很多东西:
选择第一项,在标头这里可以看到很多有用的信息,如请求的URL、请求方法、状态码等,这里我们把它拉到最下面,这个User-Agent就是我们需要用到的内容,将它复制下来。
代码实现思路:
准备工作做完了,接下来就可以尝试编写爬虫了,这里简要介绍一下思路。
首先设置好目录页的URL和请求头信息,请求头部分填入刚刚复制的User-Agent,向目录页发送request请求,并通过状态码判断请求是否成功。然后使用BeautifulSoup解析获取到的网页内容。
借助开发者工具我们可以看到,问答页的URL作为 ‘a’ 的 ‘href’ 属性藏在 <p class="p1"> 下面,所以我们首先使用soup.findAll('p', class_='p1')找到所有<p class="p1">下的父节点,遍历每一个父节点,找出name为 'a' 的子节点,提取其 ‘href’ 属性值,拼接得到问答页的URL。
接下来用类似的方法向问答页发送request请求,借助开发者工具,可知患者提问的内容是<p class="txt_ms">的文字部分,而医生的回答是<p class="sele_txt">的文字部分,所以我们可以先使用.find()找到对应节点,接下来用.get_text()获取节点的文本信息。将爬取的信息保存到事先创建好的列表中,同时计数器加一。
最后调用pandas工具包,将数据转换为DataFrame对象并保存为excel文件。
代码:
# 1 导入所需的库:requests 用于发送网络请求,BeautifulSoup 用于解析网页内容。 import requests from bs4 import BeautifulSoup # 2 data[]用于存储爬取的数据,count用于计数。 data = [] count = 0 # 3 设置请求头信息head,这里的'User-Agent'就是把刚刚复制的内容粘贴进来。 head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'} # 4 遍历从1到100页的网页 for page in range(1,101): url = "https://ask.39.net/news/141-" + str(page) + ".html" # 5 发送GET请求获取网页内容,并检查请求是否成功。 response = requests.get(url, headers=head) ''' # 状态信息,若为200则表示请求成功 # print(response.status_code) # 头信息 # print(response.headers) # 编码信息,解决中文乱码问题 # print(response.encoding) # 查看返回的网页内容,一般为html或json形式 # print(response.text) ''' if response.status_code == 200: print('正在爬取第%d页' % page) # 6 使用BeautifulSoup解析获取到的网页内容 soup = BeautifulSoup(response.text, 'html.parser') # 7 查找所有name为'p',class为'p1'的父元素 parent_elements = soup.findAll('p', class_='p1') # print(parent_elements) # 8 遍历每个找到的父元素 for parent in parent_elements: # 9 找到父元素中name为'a'的节点,提取其节点属性值 node = parent.find('a') link = node['href'] # question = node.get_text() # 10 拼接得到次级url,并向其发送get请求,这时返回的就是问答页面 url_sub = "https://ask.39.net" + link r = requests.get(url_sub, headers=head) if r.status_code == 200: # 11 解析问答网页,查找患者提问部分和医生回答部分,将其拼接为一份完整数据,同时计数器加一 soup_sub = BeautifulSoup(r.text, 'html.parser') question = soup_sub.find('p', class_='txt_ms') q = question.get_text().replace('\n','') # 先去掉'\n' q = q.replace(' ','') # 再去掉空格 # print(q) answer = soup_sub.find('p', class_='sele_txt') a = answer.get_text() # print(a) count += 1 data.append([count,q,a]) else: print('爬取第%d页出错' % page) # 12 使用 pandas 库将 data 列表转换为 DataFrame 对象,再保存为excel文件 import pandas as pd df = pd.DataFrame(data,columns=["id","question","answer"]) df.to_excel("39问医生.xlsx",index=False)