网络爬虫——python爬取豆瓣评论
一、网络爬虫概述
1. 1 网络爬虫定义
网络爬虫,又被称为网络蜘蛛(Web Spider)、网络机器人等。它根据网页地址(URL)爬取网页内容,网页地址(URL)就是我们在浏览器中输入的网站链接。例如:https://www.baidu.com;https://movie.douban.com/。
网络爬虫不仅能够复制网页信息和下载音视频,还可以做到网站的模拟登录和行为链执行。由于需要爬取的网站大多需要先登录才能正常访问,或者需要登录后的cookie值才能继续爬取,所以需要对网站模拟登录。有些网站设置了Referer防盗链,所以需要执行网页浏览行为链。
1. 2 网络爬虫途径
开发一个网络爬虫主要有两个途径,一个是根据请求包和解析包从头开始爬虫编写,也就是脚本编写爬虫,另一个是基于现行的爬虫框架,进行框架化开发。
脚本编写爬虫:Python实现了许多第三方库来帮开发者完成这个操作,比如github上开源的requests库便是发起HTTP请求,bs4解析库专注于网页信息的定位,操作网站返回的主体信息。开发重心从协议处理转化到了具体网页的数据提取。
基于框架开发爬虫:如今流行的网络爬虫框架Scrapy,其基于异步Twisted引擎,将爬虫请求的每个阶段都进行了拆分,并建立了钩子能够让开发者在每一阶段进行定制化开发,可以大大加快网络爬虫的开发速度,并且其异步特性可以很好地实现并发爬取。
1. 3 常见反爬机制
常见的反爬机制有以下几种:
User-Agent:User-Agent是一种请求头,用于表明身份的一种标识,服务器可以从User-Agent对应的值中来识别用户端使用的操作系统、浏览器、浏览器引擎、操作系统语言等。在向服务器发送的网络请求中,可以通过检测User-Agent请求头域值来判断客户端的是否为爬虫。
Referer:可以理解为来路,比如我们要打开一个产品或者影片的详情面,首先打开首页URL链接,再打开详情链接。打开详情页面的时候,Referer的信息里保存的是首页URL。是不是从网站内进入的用户,是通过Referer进行的判断,如果包含首页的URL则判断为正常用户,允许访问,如果不包含首页的URL,则判断为爬虫,不允许访问。
JavaScript混淆:JavaScript混淆是一种将JavaScript代码进行压缩和混淆的技术,旨在增加代码的复杂度和难度,使得代码难以被逆向工程师或黑客破解和篡改。
TLS指纹:也叫JA3指纹。JA3指纹通过分析TLS握手阶段中客户端和服务器之间交换的握手消息来创建一个唯一的指纹。在TLS握手期间,客户端和服务器交换一系列的握手消息,包括支持的TLS版本、密码套件、压缩算法和TLS扩展等信息。JA3指纹将这些消息中的特定字段进行哈希处理,生成一个字符串来表示客户端的TLS配置。由于不同的TLS客户端在握手消息中的字段值可能会有所不同,因此它们生成的JA3指纹也会有所不同。这使得JA3指纹可以用于识别和区分不同类型的TLS客户端,例如Web浏览器、移动应用程序、恶意软件等。
二、网络爬虫流程
网络爬虫本质是对目标服务器(URL)发起HTTP请求,并对HTTP响应做出处理,提取关键信息进行清洗入库。
图1 网络爬虫流程图
编写的网络爬虫在发起请求之后,目标网站返回指定的请求响应,通过对请求响应返回的响应体进行解析,找到需要的信息进行数据存储。如果需要翻页或者进行跳转,则从当前页面或者响应体中提取出链接再次发起请求。
2.1 发起请求
2.1.1 URL
URL 专业一些的叫法是统一资源定位符(Uniform Resource Locator),它的一般格式如下(带方括号[]的为可选项):
protocol: // hostname[:port] / path / [;parameters][?query]#fragment
URL 的格式主要由前个三部分组成:
- protocol:第一部分就是协议,例如百度使用的就是https协议;
- hostname[:port]:第二部分就是主机名(还有端口号,为可选参数),一般网站默认的端口号为80,例如百度的主机名就是www.baidu.com,这个就是服务器的地址;http://www.baidu.com:80;https://www.baidu.com:443
- path:第三部分就是主机资源的具体地址,如目录和文件名等。
例:https: //movie.douban.com/subject/35890350/?tag=国产剧&from=gaia_video
2.1.2 requests库
发起请求,我们用requests 库,它是第三方库,需要我们自己安装。
requestsy库安装:
pip install requests
requests库官方教程地址:https://requests.readthedocs.io/en/latest/
requests 库的基础方法:
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑以下各方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTML网页提交PUT请求的方法,对应于HTTP的PUT |
requests.patch() | 向HTML网页提交局部修改请求,对应于HTTP的PATCH |
requests.delete() | 向HTML网页提交删除请求,对应于HTTP的DELETE |
2.2 解析数据
2.2.1 HTML
在解析数据前,我们先要了解HTML,在浏览器的地址栏输入 URL 地址,在网页处右键单击,找到检查。然后弹出一个包含代码的页面,这个页面就是HTML信息。
2.2.1 Beautiful Soup
Beautiful Soup是Python的一个第三方库,主要帮助我们解析网页数据。
官方中文教程:https://beautifulsoup.readthedocs.io/zh_CN/latest/
Beautiful Soup的安装:
pip install beautifulsoup4
pip install lxml
html.parser 和 lxml 是 HTML 解析器,用于解析和处理 HTML 文档。可以帮助我们从 HTML 文档中提取所需的数据。html.parser相对来说比较简单,对于一般的HTML解析来说是足够的。但是在处理一些复杂的HTML文档时,可能会遇到一些局限性。在这种情况下,可能需要考虑使用 lxml 。当然,根据具体的需求和情况来选择合适的解析器是很重要的。
从 HTML 页面我们可以看到 div id=“content”、div class=“mod-bd” 等,在这里的id 和 class 就是 div 标签的属性,content 和 mod-bd 是属性值,一个属性对应一个属性值。
三、Python爬取豆瓣评论
下面是用Pyhton爬取豆瓣评论数据的实例。
import pandas as pd
import requests
from bs4 import BeautifulSoup
# 模拟浏览器头部信息,向豆瓣服务器发送消息
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/121.0.0.0 Safari/537.36'}
target = "https://movie.douban.com/subject/35890350/comments"
# 爬取页数
max_pages = 20
comments = []
for page in range(max_pages):
# 获取HTML页面信息
response = requests.get(url = target
+ '?start=' + str(page * 20)
, headers = headers
)
response.encoding = 'utf-8'
# print(response.text)
# 解析HTML信息并提取评论信息
soup = BeautifulSoup(response.text, 'lxml')
# print(soup)
# 根据网页结构定位评论区域
# comments_section = soup.find('div', {'class': 'mod-bd'})
# print(comments_section)
# 提取评论信息
# comment_elements = comments_section.find_all('span', {'class': 'short'})
comment_elements = soup.find_all('span', {'class': 'short'})
# print(comment_elements)
for element in comment_elements:
comments.append(element.text.strip())
# print(comments)
# 数据存储到EXCEL表
# 创建一个包含评论内容和评论时间的数据框
data = {'评论内容': comments}
df = pd.DataFrame(data)
# print(df)
# 指定输出的Excel文件名
output_filename = "douban_comments.xlsx"
# 将DataFrame保存为Excel文件
df.to_excel(output_filename, index=False, engine='openpyxl')
print(f'数据已保存到 {output_filename}')