一.什么是网络爬虫
爬虫,是一种自动抓取网页信息的程序或脚本。
它遵循预设的规则,专门用于在网络上自动抓取、检索和收集万维网(WWW)上的信息。
网络爬虫的核心功能是模拟人类用户浏览网页的行为,通过向网站服务器发送HTTP(或HTTPS)请求,获取网页的HTML、XML、JSON等格式的响应数据,然后对这些数据进行解析,以提取有价值的信息。
二.爬虫工作原理与基本流程
包括以下几个步骤:
- 初始化
- 明确自己要爬取的网站或者网页范围,以及我们需要抓取的具体信息(如新闻标题、商品价格、评论等)。
- 定义起始URL列表,这是爬虫开始抓取的网页地址
- 设置爬虫参数,如最大深度、抓取速率、HTTP请求头(如User-Agent、Referer、Cookies等)等。
什么是URL?
URL(Uniform Resource Locator,统一资源定位符)是一种标准化的互联网地址,用于唯一且确切地标识和定位互联网上的某个资源。URL 是 Web 浏览器用来访问网页、文件、图像、视频等各种在线内容的标准地址格式。
一个完整的 URL 通常由以下几个部分组成:
协议(Protocol): 定义了访问资源所使用的网络协议,如 http://、https://(安全的 HTTP)、ftp://(文件传输协议)、mailto:(电子邮件链接)等。最常见的协议是 HTTP 和 HTTPS,它们用于访问网页内容。
域名(Domain Name): 指定服务器的互联网名称,例如 www.example.com。域名是人类可读的、易于记忆的互联网地址,通过 DNS(域名系统)解析后,会映射到对应的 IP 地址,从而使得浏览器能够找到并连接到正确的服务器。
端口(Port Number)(可选): 有时会在域名后面跟一个冒号和一个数字来指定服务器的端口号。如果不指定,HTTP 通常默认使用端口 80,HTTPS 默认使用端口 443。例如:www.example.com:8080。如果使用的是默认端口,则通常省略不写。
路径(Path)(可选): 描述了服务器上特定资源的位置,由斜杠 / 分隔的一系列目录名和/或文件名组成。例如:/news/latest 或 /images/profile.jpg。
查询参数(Query Parameters)(可选): 以问号 ? 开始,接着是一系列键值对,每个键值对之间用 & 分隔。键与值之间用等号 = 连接。查询参数提供了额外的信息来进一步指定或过滤请求的资源。例如:?category=news&sort=latest。
片段标识符(Fragment Identifier)(可选): 以井号 # 开始,后面跟着一个字符串,用于指示资源内部的特定位置或锚点。浏览器不会将片段标识符发送到服务器,它仅用于在客户端(即浏览器)内导航到文档内的特定部分。例如:#section3。
一个典型的 URL 示例:
https://www.example.com:8080/news/latest?category=world&sort=recent#comments
在这个例子中:
协议:https://
域名:www.example.com
端口:8080
路径:/news/latest
查询参数:category=world&sort=recent
片段标识符:#comments
URL 作为一种全球统一的资源定位机制,使得用户和应用程序能够方便、准确地访问和共享互联网上的各种信息资源。
什么是HTTP请求头
HTTP请求头(HTTP Request Headers)是客户端(通常是Web浏览器或爬虫)在发起HTTP请求时,随请求一同发送到服务器的一组键值对形式的数据。这些头部信息提供了有关请求的附加细节,帮助服务器理解请求的性质、客户端环境以及请求内容的处理方式。请求头与请求方法(如GET、POST)、请求URI(统一资源标识符)以及可选的请求体(如表单数据或文件)共同构成了完整的HTTP请求。
常见的HTTP请求头包括但不限于:
Host: 指定请求的目标主机名和可选端口号。这对于处理同一台服务器上托管多个域名(虚拟主机)的情况尤为重要。
User-Agent: 描述发起请求的客户端软件信息,如浏览器类型、版本、操作系统等。服务器常利用此信息来定制响应内容或进行用户代理统计。
Cookie: 传递与服务器建立的会话相关的状态信息。客户端在后续请求中发送服务器先前设置的Cookie,服务器据此识别用户身份、维持会话状态等。
- 发送请求
- 根据目标URL和请求参数,使用如requests库等工具构造HTTP GET或POST请求。向目标服务器发送请求,等待响应。
- 可能涉及处理cookies、session信息,模拟登录、处理验证码,以及使用代理IP等以绕过网站的反爬机制
- 接收响应
- 服务器返回网页内容,通常为HTML或其他结构化的数据格式,包含状态码、响应头和正文(网页内容)。
- 检查状态码,如为200(OK)则继续处理,否则根据状态码判断是否需要重试、跳过或记录异常。
- 数据解析
- 使用如BeautifulSoup、lxml、PyQuery等库解析HTML文档,或者使用json模块解析JSON数据。
- 根据预定义的规则或XPath、CSS选择器等提取所需信息,如文本内容、链接、图片、元数据等。
- 数据储存
- 将抓取到的数据保存到合适的数据结构(如列表、字典)或持久化存储,如CSV文件、JSON文件、数据库(如MySQL、MongoDB)或云存储服务(如Amazon
S3)。
- 链接发现与调度
- 从当前页面中提取出新的链接(后续要抓取的URL),添加到待抓取队列中。
- 检查新发现的链接是否已抓取过或在待抓取队列中,避免重复抓取。
- 将符合条件的新链接添加到待抓取URL队列中,如优先级队列、FIFO队列等。
- 应用策略(如广度优先、深度优先、优先级队列等)决定下一个要抓取的URL。
- 循环与终止条件
- 重复上述过程,直到达到预设的停止条件,如达到最大抓取深度、抓取指定数量的页面、抓取时间限制、无更多待抓取链接等。
- 后期处理与分析
- 对抓取到的数据进行清洗,去除噪声、填充缺失值、转换数据格式等,提高数据质量。
- 使用统计分析、数据挖掘、机器学习等方法对清洗后的数据进行深入分析,提取有价值的信息和洞察。
- 将分析结果可视化,如生成图表、报告、仪表板等,便于理解和沟通。
三.Python爬虫环境搭建与必备工具
- Python环境安装与配置
推荐使用Anaconda或Miniconda来创建并管理Python虚拟环境,我使用的是Anaconda。
- 常用爬虫库与工具介绍
requests:用于发送HTTP请求。
BeautifulSoup、PyQuery、lxml:用于解析HTML和XML文档。
pandas:用于数据清洗、整理与分析。
scrapy:强大的爬虫框架,适用于大型、复杂项目的开发。
fake_useragent:生成随机User-Agent,避免被网站识别为爬虫。
proxies:代理IP的使用,应对反爬策略。
Selenium、Playwright等:模拟浏览器行为,处理动态加载内容或需要交互的情况。
使用 pip install 库名 的方法可以安装对应库
四.实战演练:编写你的第一个Python爬虫
下面是一个Python爬虫程序,用于爬取某视频网站上最受好评的电影信息,并将这些信息存储到excel表格中。
import time # 导入时间模块
import traceback # 导入异常追踪模块
import requests # 导入HTTP请求库
from lxml import etree # 导入处理XML数据的模块
import re # 导入正则表达式模块
from bs4 import BeautifulSoup # 导入解析HTML和XML文档的库
from lxml.html.diff import end_tag # 导入比较HTML文档差异的函数
import json # 导入处理JSON数据的模块
import pymysql # 导入操作MySQL数据库的库
def get_souhu():
url='https://film.sohu.com/list_0_0_0_2_2_1_60.html?channeled=1200100000'
#最新上架
new_url='https://film.sohu.com/list_0_0_0_2_1_1_60.html?channeled=1200100000'
#本周热播
week_url='https://film.sohu.com/list_0_0_0_2_0_1_60.html?channeled=1200100000'
#创建字典存放HTTP请求的头部信息
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
}
#初始化列表
templist=[]
dataRes=[]
#最受好评
for i in range(1,31):
url_1 = 'https://film.sohu.com/list_0_0_0_2_2_'
#将整型变量i转换为字符串str(i),这里的i通常是一个循环变量,用于遍历不同的页码。
auto = str(i)
url_2 = '_60.html?channeled=1200100000'
#将上述三个部分拼接起来,形成完整的请求URL。当i值变化时,url将指向不同的页数。
url = url_1 + auto + url_2
'''
使用requests库的get()方法,向拼接得到的url发送一个GET请求。
这里传入了前面定义的headers字典作为请求头,包含了User-Agent等信息,
模拟浏览器行为以降低被识别为爬虫的风险。
'''
response = requests.get(url, headers)
#设置响应的编码为utf-8。这样在后续处理响应内容时,会使用该编码进行解码,确保文本数据的正确解析。
response.encoding = 'utf-8'
#从响应对象response中提取文本内容,赋值给变量page_text。page_text现在包含了所请求页面的HTML源代码。
page_text = response.text
'''将之前获取的HTML文本page_text传递给BeautifulSoup构造函数,
使用lxml解析器创建一个BeautifulSoup对象soup。
soup是一个可遍历、查询的DOM树结构,方便我们从中提取所需信息。
'''
soup = BeautifulSoup(page_text, 'lxml')
'''
使用BeautifulSoup的select()方法,传入CSS选择器字符串'.movie-list>li'。
这个选择器表示选择所有直接子元素为li的class属性为movie-list的元素。
在实际网页结构中,这通常对应电影列表容器下的各个电影项。
select()方法返回一个包含所有匹配元素的列表li_list。
'''
li_list = soup.select('.movie-list>li')
#print(len(li_list)):打印li_list的长度,即提取到的电影列表项数量,用于直观了解当前页面包含多少部电影。
print(len(li_list))
#检查li_list的长度是否为0。如果为0,说明当前页面没有找到任何电影列表项。
if(len(li_list) == 0):
print("最受好评爬取结束!")
#进一步检查dataRes列表(存储爬取到的所有电影数据)是否非空。如果非空,说明之前已经成功抓取到一些电影数据。
if(len(dataRes) != 0):
return dataRes
#对之前获取的电影列表项列表li_list进行遍历
for li in li_list:
#将当前电影列表项li转换为字符串形式,便于再次使用BeautifulSoup解析。
li_text = str(li)
#将字符串li_text传递给BeautifulSoup构造函数,创建一个新的BeautifulSoup对象li_soup,用于解析当前电影列表项的详细内容。
li_soup = BeautifulSoup(li_text,'lxml')
#在li_soup中使用find()方法查找类名为v_name_info的div元素,并获取其文本内容,赋值给变量name。这通常是电影的名称。
name = li_soup.find('div',class_ = "v_name_info").text
#将电影名称name添加到临时列表templist中。
templist.append(name)
#在li_soup中查找类名为v_score的span元素,并获取其文本内容,赋值给变量score。这通常是电影的评分。
score = li_soup.find('span',class_='v_score').text
#截取score变量最后四个字符(即评分数值),因为评分可能包含额外的文字描述,如“评分:”或“/10”,这里仅保留数字部分。
score = score[-4:-1]
templist.append(score)
#在li_soup中查找target属性为"_blank"的a元素(通常指向外部链接),并获取其href属性值(即链接地址),赋值给变量path。这通常是电影详情页的链接。
path = li_soup.find('a',target="_blank")['href']
templist.append(path)
#这里直接给变量state赋值为字符串"VIP",表示这部电影的播放状态为VIP专享。
state = "VIP"
templist.append(state)
print(templist)
#将当前电影的详细信息列表templist追加到最终结果集dataRes,积累所有爬取到的电影数据。
dataRes.append(templist)
#清空临时列表templist,准备处理下一个电影列表项。
templist = []
print("-------------------------------------------")
return dataRes
import pandas as pd
def save_to_excel(data, filename='sohu_movies.xlsx'):
# 将数据转换为DataFrame
df = pd.DataFrame(data)
# 写入Excel文件
df.to_excel(filename, index=False)
# 主函数,执行爬取任务并保存结果至Excel
if __name__ == '__main__':
data = get_souhu()
save_to_excel(data)