> 本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
一.引言
在当今信息爆炸的时代,网络爬虫成为了获取和处理网络数据的重要工具。Python,以其简洁的语法和强大的库支持,成为了编写爬虫的首选语言。本文将详细介绍如何使用Python进行网络爬虫的编写,包括发送请求、解析数据以及保存结果。
二.环境准备
#发请求的库
pip install requests
#解析库
pip install parsel
三.知识点概述(附案例)
(一)requestst概述
requests模块是一个网络请求模块,可以帮助我们模拟成客户端去请求服务器的数据。 我们可以在浏览器中抓取到这些请求与响应的内容,那么我们可以“伪造”请求吗?也就是不再通过浏览器发送这些数据,而是通过Python来模拟浏览器发送请求。答案是可行的。而Requests模块就可以完成这种功能。 还有其他库吗? 回答也是肯定的,例如 urllib , urllib2 等模块。但是目前来说 Requests 模块是最流行的。而且也是做好用的模块。
(二)请求方法
1.get 请求
一般情况下,只从服务器获取数据下来,并不会对服务器资源产生任何影响的时候会使用 get 请求。
import requests
#案例链接:https://movie.douban.com/top250
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
}
url = "https://movie.douban.com/top250"
params = {
"start": "0",
"filter": ""
}
response = requests.get(url, headers=headers, params=params)
2.post 请求
向服务器发送数据(登录)、上传文件等,会对服务器资源产生影响的时候会使用post 请求。
(1)Form Data 模式
post请求请求参数Form Data ---------------------------------> 用data关键字传递
import requests
#案例链接:https://www.kfc.com.cn/kfccda/storelist/index.aspx
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx'
params = {'op': 'keyword'} # 查询参数
data = { # 请求参数
'cname': '',
'pid': '',
'keyword': '北京',
'pageIndex': '1',
'pageSize': '10'
}
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'}
# data是构建post请求的请求参数关键字
response = requests.post(url=url, params=params, data=data, headers=headers)
(2)Request Payload 模式
post请求请求参数Request Payload ---------------------------------> 用json关键字传递
import requests
#案例链接:https://www.zfcg.sh.gov.cn/site/category?parentId=137027&childrenCode=ZcyAnnouncement&utm=site.site-PC-39935.959-pc-websitegroup-navBar-front.3.e7740270bd1411ef87a395a2e57c85a7
url = 'http://www.zfcg.sh.gov.cn/portal/category'
json_data = {"pageNo": 1, "pageSize": 15, "categoryCode": "ZcyAnnouncement1", "_t": 1734505402000}
# json 以json数据提交的请求参数
response = requests.post(url=url, json=json_data)
(三)解析语法
1.css选择器
(1)标签、类和id选择器
- 标签选择器其实就是我们经常说的html代码中的标签。例如html、span、p、div、a、img等等
- 类选择器在我们今后的css样式编码中是最常用到的,它是通过为元素设置单独的class来赋予元素样式效果。
- D选择器类似于类选择符,作用同类选择符相同,但也有一些重要的区别。
选择器 | 例子 | 例子描述 |
---|---|---|
.class | .intro | 选择 class=“intro” 的所有元素。 |
#id | #firstname | 选择 id=“firstname” 的所有元素。 |
* | * | 选择所有元素。 |
element | p | 选择所有 元素。 |
element,element | div,p | 选择所有
元素和所有
元素。 |
element element | div p | 选择
元素内部的所有
元素。 |
element>element | div>p | 选择父元素为
元素的所有
元素。 |
[attribute] | [target] | 选择带有 target 属性所有元素。 |
(2)伪类选择器
语法 | 示例 | 描述 |
---|---|---|
:last-of-type | p:last-of-type | 选择满足p语法元素的最后一个元素 |
:not(selector) | :not§ | 选择所有p以外的元素 |
:nth-child(n) | p:nth-child(2) | 选择满足p语法元素的第二个元素 |
:nth-last-child(n) | p:nth-last-child(2) | 选择满足p语法元素的倒数的第二个元素 |
接着上述get请求做css语法解析
import csv
import requests
import parsel
def get_data(page):
print(f'==============正在抓取{page}页===================')
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
}
url = "https://movie.douban.com/top250"
params = {
"start": f"{(page-1)*25}",
"filter": ""
}
response = requests.get(url, headers=headers, params=params)
parsel_text = parsel.Selector(response.text)
##css语法解析
lis = parsel_text.css('.grid_view li') #一次提取
#二次提取
for li in lis:
movie_name = li.css('.title:nth-child(1)::text').get() #标题
movie_score = li.css('.star .rating_num::text').get() #评分
info = li.css('.bd>p::text').getall()
info = [i.strip().replace('\xa0','') for i in info]
info1 = info[1].split('/')
movie_time = info1[0]
movie_area = info1[-2]
movie_type = info1[-1]
print({
'movie_name' :movie_name,
'movie_score' :movie_score,
'movie_time' :movie_time,
'movie_area' :movie_area,
'movie_type' :movie_type,
})
if __name__ == '__main__':
for page in range(1,11):
get_data(page)
2.xpath节点提取
认识树的结构
认识xpath的节点关系
(1)xpath语法
XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
下面列出了最有用的表达式:
表达式 | 描述 |
---|---|
nodename | 选中该元素。 |
/ | 从根节点选取、或者是元素和元素间的过渡。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。跨节点获取标签 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 定位, 选取属性值 |
text() | 选取文本。 |
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
路径表达式 | 结果 |
---|---|
bookstore | 选择bookstore元素。 |
/bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//book/title/@lang | 选择所有的book下面的title中的lang属性的值。 |
//book/title/text() | 选择所有的book下面的title的文本。 |
- 选取未知节点
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
node() | 匹配任何类型的节点。 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/* | 选取 bookstore 元素的所有子元素。 |
//* | 选取文档中的所有元素。 |
//title[@*] | 选取所有带有属性的 title 元素。 |
接着上述get请求做xpath语法解析
import requests
from parsel import Selector
def get_data(page):
print(f'==============正在抓取{page}页===================')
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
}
url = "https://movie.douban.com/top250"
params = {
"start": f"{(page-1)*25}",
"filter": ""
}
response = requests.get(url, headers=headers, params=params)
selector = Selector(response.text)
##xpath语法解析
lis = selector.xpath('//ol[@class="grid_view"]/li')
for li in lis:
movie_name = li.xpath('.//div[@class="info"]/div[@class="hd"]/a/span[1]/text()').get() # 标题
movie_score = li.xpath('.//span[@class="rating_num"]/text()').get() # 评分
info = li.xpath('.//div[@class="bd"]/p/text()').getall()
info = [i.strip().replace('\xa0', '') for i in info]
# print(info)
info1 = info[1].split('/')
movie_time = info1[0]
movie_area = info1[-2]
movie_type = info1[-1]
print({
'movie_name': movie_name,
'movie_score': movie_score,
'movie_time': movie_time,
'movie_area': movie_area,
'movie_type': movie_type,
})
if __name__ == '__main__':
for page in range(1, 11):
get_data(page)
(四)数据保存(csv)
csv文件格式是一种通用的电子表格和数据库导入导出格式。最近我调用RPC处理服务器数据时,经常需要将数据做个存档便使用了这一方便的格式。
这边主要用的是csv中的字典写入来实现数据持久化的
#创建一个csv
f = open(‘豆瓣top250.csv’, mode=‘w’, encoding=‘utf-8’, newline=‘’)
#表头形式构建
csv_write = csv.DictWriter(f, [
‘movie_name’,
‘movie_score’,
‘movie_time’,
‘movie_area’,
‘movie_type’,
])
#写入表头
csv_write.writeheader()
dic = {‘movie_name’: ‘二十二’, ‘movie_score’: ‘8.7’, ‘movie_time’: ‘2015’, ‘movie_area’: ‘中国大陆’, ‘movie_type’: ‘纪录片’}
#csv字典写入数据
csv_write.writerow(dic)
#关闭csv
f.close()
接着上述实现了解析语法的案例
import csv
import requests
import parsel
def get_data(page,csv_write):
print(f'==============正在抓取{page}页===================')
headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6",
"cache-control": "max-age=0",
"priority": "u=0, i",
"sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "same-origin",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
}
url = "https://movie.douban.com/top250"
params = {
"start": f"{(page-1)*25}",
"filter": ""
}
response = requests.get(url, headers=headers, params=params)
parsel_text = parsel.Selector(response.text)
lis = parsel_text.css('.grid_view li')
for li in lis:
movie_name = li.css('.title:nth-child(1)::text').get() #标题
movie_score = li.css('.star .rating_num::text').get() #评分
info = li.css('.bd>p::text').getall()
info = [i.strip().replace('\xa0','') for i in info]
info1 = info[1].split('/')
movie_time = info1[0]
movie_area = info1[-2]
movie_type = info1[-1]
print({
'movie_name' :movie_name,
'movie_score' :movie_score,
'movie_time' :movie_time,
'movie_area' :movie_area,
'movie_type' :movie_type,
})
csv_write.writerow({
'movie_name' :movie_name,
'movie_score' :movie_score,
'movie_time' :movie_time,
'movie_area' :movie_area,
'movie_type' :movie_type,
})
if __name__ == '__main__':
f = open('豆瓣top250.csv', mode='w', encoding='utf-8', newline='')
csv_write = csv.DictWriter(f, [
'movie_name',
'movie_score',
'movie_time',
'movie_area',
'movie_type',
])
csv_write.writeheader()
for page in range(1,11):
get_data(page,csv_write)
f.close()