当前位置: 首页 > article >正文

Python爬虫基础总结笔记

笔记主体内容来自尚硅谷Python爬虫小白教程,老师课讲得很好,非常推荐!!!

1. 爬虫简介

将整个互联网看作是蜘蛛网,各网站数据为猎物,程序员为狩猎者,因此爬虫顾名思义即程序员通过各种手段获取互联网上的数据。

2. urllib

urllib 是 python 标准库种用于发送网络请求的库,掌握基本命令可以便于批量获取网络数据

2.1 访问服务器

import urllib.request
url = 'http://www.baidu.com'
# 模拟浏览器访问(返回的是HTTPResponse对象)
response = urllib.request.urlopen(url)
# 获取网页内容,读取到的是二进制数据,通过decode解码为utf-8形式
# response还有readlines,getcode,geturl,getheaders等方法
html = response.read().decode('utf-8')

2.2 下载资源

传入资源地址, 下载图片,视频等资源

import urllib.request
# 图片地址
url_retrieve = 'https://img1.baidu.com/it/u=959337756,4186275445&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=889'
# 下载图片并存储到本地,重命名为1.jpg
urllib.request.urlretrieve(url_retrieve, '1.jpg')

2.3 自定义请求对象

为什么需要?

https 请求头部中有 User Agent 字段,使得服务器能够识别客户使用的操作系统及版本,CPU 类型、浏览器及版本等信息,而当使用脚本发出普通请求时,这一字段为空,此时服务端返回的响应内容会有所保留。使用自定义请求对象添加此部分信息即可解决问题。

User Agent 字段获取方式如下

image-20250102171743218
import urllib.request
url = 'https://www.baidu.com'
header = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36'}
# 自定义请求对象,post请求数据由data关键字传入字典
request = urllib.request.Request(url, headers=header)
# 发送请求
response = urllib.request.urlopen(request)
# 读取响应内容
content = response.read().decode('utf-8')

2.4 请求编码

在 request 中传入中文无法被识别,因此需要将文本转换为 Unicode 格式再传入

import urllib.parse
# 得到周杰伦的unicode编码
name = urllib.qarse.quote('周杰伦')
# 转换多个参数且用&连接【可直接与get请求拼接】
data = {
    'wd':'周杰伦',
    'sex':'男'
}
# wd=xxxx&sex=yyyy
# 如果用于post请求则还需要使用encode('utf-8')转为字节流
a = urllib.parse.urllencode(data)

2.5 代理服务器

当一个IP地址短时间内多次向服务器发送请求时,可能会被拉黑,此时可以使用代理服务器模拟多用户,实现反爬

import urllib.request
url = 'http://www.baidu.com/s?wd=IP'
header = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36'
}
# 云平台查询得到的IP地址【百度搜索“快代理”】
proxies = {
    'http': '8.130.71.75:3128'
}
request = urllib.request.Request(url, headers=header)
# handler可以自定义更复杂的头部信息,此处添加访问IP地址
handler = urllib.request.ProxyHandler(proxies=proxies)
# handler固定使用步骤:handler,builder_opner,open
opener = urllib.request.build_opener(handler)
# 发送请求
response = opener.open(request)
# 读取响应内容
content = response.read().decode('utf-8')
with open('main.html', 'w', encoding='utf-8') as f:
    f.write(content)

若手上有大量IP地址,可以通过代理池的方式随机选择访问IP,防止地址被封

proxies_pool = [{'http': '8.130.71.75:1111'},{'http': '8.130.71.75:2222'}]
proxies = random.choice(proxies_pool)

3. 解析网页

3.1 XPath

Python 使用 XPath 提取网页目标元素依赖于 lxml 库

from lxml import etree
# 解析本地的html文件
html_tree = etree.parse('xx.html')
# 解析服务器响应的response
html_tree = etree.HTML(response.read().decode('utf-8'))
# xpath路径解析后结果,返回一个列表
res = html_tree.xpath('xpath路径')

3.2 JSonPath

Python使用 jsonpath 第三方库提取 json 格式响应数据,jsonpath只能解析本地文件

import json 
import jsonpath
# 加载json数据
obj = json.load('xxx')
# 具体语法使用时查询即可
res = jsonpath.jsonpath(obj,'jsonpath语法')

3.3 BeautifulSoup

bs4 库作用与 lxml 库类似,但是效率低,优点是接口设计更符合使用习惯

from bs4 import BeautifulSoup
# 服务器响应的文件生成对象
soup = BeautifulSoup(response.read().decode(),'lxml')
# 本地文件生成对象
soup = BeautifulSoup(open('xx.html'),'lxml')

常用方法

# 找到第一个<a>
soup.a
# 返回第一个<a>标签的所有属性,以字典的形式存储
soup.a.attrs
# 返回当前定位元素中value属性值
soup.attrs.value

# 找到第一个title为xxx且classw为yyy的<a>
soup.find('a',title='xxx',class_='yyy')
# 找到所有<a>和<span>标签,只返回前两个
soup.find_all(['a','span'],limit=2)

# 返回所有<a>,逗号分隔拼接可以获取多个不同标签
soup.select('a')
# 支持类选择器【.】,Id选择器【#】以及属性选择器
# 支持层级选择器【空格是不严格子代,>是严格子代】
# 查找拥有id的属性的<li>标签,也可以指定id为具体值【用双引号】
soup.select('li[id]')

# 获取节点文本内容
obj.get_text()
# 通过key,value的格式可以获得对应属性值
obj['name']

4. UI自动化

有些网页当使用请求的方式无法获得所有数据,因此需要使用UI自动化的方式获取目标数据

Selenium 提供了 UI 自动化方案,但是加载页面效率较低,可以考虑使用无浏览器界面的自动化

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
# 获得浏览器对象
def share_brower(browser_path='D:\Chrome\Google\Chrome\Application\chrome.exe'):
    # 驱动路径
    option = Options()
    # 设置浏览器启动地址
    option.binary_location = browser_path
    option.add_argument('--headless')  # 无头模式
    option.add_argument('--disable-gpu')  # 禁用gpu加速
    # 创建浏览器对象
    browser = webdriver.Chrome(options=option)
    return browser

# 上网
url = 'http://www.baidu.com/'
browser = share_brower()
browser.get(url)
# 截图
browser.save_screenshot('baidu.png')

5. requests库

requests 是一个用于发送请求的第三方库,相对于 urllib 而言操作更加便捷

# request 发送请求后得到的返回值记为 r
# 得到返回文本
r.text 
# 定制编码方式
r.encoding 
# 获取请求的ur1
r.url
# 返回文本的字节类型
r.content
# 响应的状态码
r.status_code
# 响应的头信息
r.headers

发送请求样例

若要保证多个请求在同一个域里,可以通过获取 session 对象再进行请求调用

import requests
url = 'https://www.baidu.com/s'
# 请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36'
}
# 请求参数
data = {
    'wd': '广东'
}
# 传入,post请求中params对应是data关键字
r = requests.get(url, params=data, headers=headers)
# 指定编码
r.encoding = 'utf-8'
print(r.text)

开启代理

# 只需要准备好ip和端口,传入proxies参数即可
proxy = {
    'http':'xxx.xxx.xxx.xxx:yyy'
}
request.get(url,params,headers,proxies=proxy)

6. scrapy库

Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘、信息处理或存储历史数据等一系列的程序中

6.1 基础结构介绍

# 创建爬虫项目,名称为scrapy_test_project
scrapy startproject scrapy_test_project
image-20250120161213582

项目组成介绍

项目名称
	项目名称
    	spiders
        	__init__.py
            自定义爬虫文件		# 实现爬虫核心功能的文件
    __init__.py
    items.py				# 定义数据结构的地方,是一个继承自scrapy.Item的类
    middlewares.py			# 中间件,代理
    pipelines.py			# 管道文件,里面只有一个类,用于处理下载数据的后续处理,默认是300						      优先级,值越小优先级越高(1-1000)
    settings.py				# 配置文件,比如是否遵守robots协议等

进入到 spiders 目录下,生成爬虫文件

# 创建一个叫baidu的爬虫,用于爬取www.baidu.com内容
scrapy genspider baidu www.baidu.com
# 执行爬虫【在根目录下的settings中注释ROBOTSTXT_OBEY = True】
scrapy crawl baidu
image-20250120163346089

response的属性和方法

# 获取响应的字符串
response.text	
# 获取的是二进制数据
response.body
# xpath过滤
response.xpath()
# 提取selector对象的data属性值
response.extract()
# 提取selector列表的第一个数据
response.extract_first()

执行过程简介

image-20250120171422288
# 开启调试模式,可在控制台查看response相关信息
scrapy shell 目标网站
image-20250121095130473

settings.py 日志设置

# 设置日志显示等级(CRITICAL,ERROR,WARNING,INFO,DEBUG)
# 默认等级是DEBUG,只要出现了DEBUG或以上等级的日志都会被打印
LOG_LEVEL = DEBUG
# 将屏幕显示的信息全部记录到文件中,屏幕不再显示,文件以.log结尾
LOG_FILE = xxx.log

6.2 爬取当当网数据实战

我们的目标是获取青春爱情文学前三页的所有书名,图片与价格信息

image-20250122142350141
  1. 创建爬虫项目,手动创建 books 以及 books/img 目录方便后续存储相关信息

    # 创建名为scrapy_dangdang的爬虫项目
    scrapy startproject scrapy_dangdang
    
    image-20250122143832360
  2. 编辑数据结构文件 items.py ,将需要存储的变量都交由框架管理

    import scrapy
    class ScrapyDangdangItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        # 要下载的数据都有什么
        # 图片
        src = scrapy.Field()
        # 名字
        name = scrapy.Field()
        # 价格
        price = scrapy.Field()
    
  3. 在 spiders 目录下创建爬虫核心文件,指明初始页面并命名为 dangdang

    scrapy genspider dangdang https://category.dangdang.com/pg1-cp01.01.02.00.00.00.html
    

    根据处理逻辑编辑该文件

    import scrapy
    from scrapy_dangdang.items import ScrapyDangdangItem
    class DangdangSpider(scrapy.Spider):
        # 爬虫名称
        name = "dangdang"
        allowed_domains = ["category.dangdang.com"]
        start_urls = ["https://category.dangdang.com/pg1-cp01.01.02.00.00.00.html"]
        # 需要爬取的文章页码
        page = 1
        # 执行爬虫文件时自动调用此方法
    
        def parse(self, response):
            # 根据调试网页获得的目标xpath路径
            # src = '//ul[@class='bigimg']//li/a[1]/img/@data-original'
            # alt = '//ul[@class="bigimg"]//li/a[1]/img/@alt'
            # price = '//ul[@class='bigimg']//li/p[@class='price']/span[1]/text()'
            li_list = response.xpath('//ul[@class="bigimg"]//li')
            for li in li_list:
                # 懒加载图片,data-original属性值是真实地址
                src = li.xpath('.//a[1]/img/@data-original').extract_first()
                # data-original不存在时,使用src数属性值作为地址
                if src is None:
                    src = li.xpath('.//a[1]/img/@src').extract_first()
                name = li.xpath('.//a[1]/img/@alt').extract_first()
                price = li.xpath(
                    './/p[@class="price"]/span[1]/text()').extract_first()
                # 将解析的目标值封装并交由管道处理
                book = ScrapyDangdangItem(src=src, name=name, price=price)
                yield book
            # 爬取前3页的数据
            if self.page <= 2:
                self.page += 1
                # 新页面地址
                url = f'http://category.dangdang.com/pg{self.page}-cp01.01.02.00.00.00.html'
                # scrapy.Request是scrapy的get请求,callback传入需要调用的下一个函数
                # 此处是向url发送get请求后重新调用parse方法
                yield scrapy.Request(url, callback=self.parse)
    
  4. 编辑管道文件 pipelines.py,用于下载处理爬虫所返回的数据

    # useful for handling different item types with a single interface
    from itemadapter import ItemAdapter
    import urllib.request
    # 用于存储json文件
    class ScrapyDangdangPipeline:
        # 在爬虫文件开始前执行的方法
        def open_spider(self, spider):
            self.res = []
        def process_item(self, item, spider):
            # 将单引号替换为双引号
            temp = str(item).replace('\'', '\"')
            self.res.append(temp)
            return item
        # 在爬虫文件结束后执行的方法
        def close_spider(self, spider):
            with open('./books/books.json', 'w', encoding='utf-8') as f:
                # 以逗号作为分隔符将元素拼接并写入json文件
                f.write(f'[{",".join(self.res)}]')
    
    # 用于处理图片文件
    class DangDangDownloadPipeline:
        # 在爬虫文件开始前执行的方法
        def open_spider(self, spider):
            pass
        def process_item(self, item, spider):
            pic_url = 'http:' + item.get('src')
            pic_name = './books/img/' + item.get('name') + '.jpg'
            urllib.request.urlretrieve(pic_url, pic_name)
            return item
        # 在爬虫文件结束后执行的方法
        def close_spider(self, spider):
            pass
    

    管道处理设计完毕后,还需要配合 settings.py 设置管道除了优先级,同时记得注释ROBOTSTXT_OBEY = True【君子协议,为 True 则不允许爬取特定网站】

    ITEM_PIPELINES = {
        # 值越小,管道优先级越高
        "scrapy_dangdang.pipelines.ScrapyDangdangPipeline": 300,
        "scrapy_dangdang.pipelines.DangDangDownloadPipeline": 301,
    }
    
  5. 进入 spiders 目录,执行爬虫文件,完成资源爬取

    scrapy crawl dangdang
    
    image-20250122150853367 image-20250122150805960

6.3 post请求处理

先前使用 start_urls 的方式指定初始访问界面,但在post请求中由于需要请求头,因此无法使用这种方式,所以针对post请求我们需要重新定义一种方式进行处理

import scrapy
import json

class TransPostSpider(scrapy.Spider):
    name = "trans_post"
    allowed_domains = ["fanyi.baidu.com"]
    # post请求需要指定请求体,start_urls无法做到
    # start_urls = ["https://fanyi.baidu.com/mtpe-individual/multimodal#/"]
    # 自定义请求体发送post请求

    def start_requests(self):
        url = 'https://fanyi.baidu.com/sug'
        data = {
            'kw': '你好'
        }
        # scrapy中的post,callback指定请求完毕后后续处理的函数
        yield scrapy.FormRequest(url, formdata=data, callback=self.parse)

    def parse(self, response):
        content = json.loads(response.text)
        print(content)

7. CrawlSpider

CrawlSpider 继承至 scrapy.Spider,在解析网页内容的时候,它可以根据链接规则提取出指定的链接,然后再向这些链接发送请求,非常适用于爬取网页后需要提取链接进行二次爬取的情况。

其爬虫类创建命令稍有不同

# 创建爬虫项目
scrapy startproject scrapy_dushu
# 爬虫类名称为read,爬取网站为www.dushu.com
scrapy genspider -t crawl read https://www.dushu.com/book/1107_1.html

使用链接提取器过滤得到目标链接

scrapy.linkextractors.LinkExtractor(
	allow=(),	# 通过正则表达式过滤
    restrict_xpaths=(),	# 通过xpath过滤(定位到a元素即可)
)

爬取读书网实战

我们的目标是获取计算机网络/读书网首页所能看见页面里所有书名,图片链接信息

image-20250123105450352

除了爬虫核心函数有所不同,其余setting,pipeline,items的用法类似,此处不再赘述,根据需求自行修改即可

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_dushu.items import ScrapyDushuItem


class ReadSpider(CrawlSpider):
    name = "read"
    allowed_domains = ["www.dushu.com"]
    start_urls = ["https://www.dushu.com/book/1107_1.html"]

    rules = (Rule(
        LinkExtractor(
            # 正则表达式写法
            # allow=r'/book/1107_\d+\.html',
            # xpath写法
            restrict_xpaths=("//div[@class='pages']/a")
        ),
        # 重复调用的函数名称
        callback="parse_item",
        # 为False时不会在新页面中再次调用匹配规则,即最初过滤得到的链接不会实时变动
        follow=False),)

    def parse_item(self, response):
        # 定位到所有图片
        img_list = response.xpath(
            "//div[@class='book-info']//a/img")
        for img in img_list:
            # 获取图书名称
            name = img.xpath("./@alt").extract_first()
            # 获取图书封面图片地址
            src = img.xpath("./@data-original").extract_first()
            if src is None:
                src = img.xpath("./@src").extract_first()
            # 封装为数据结构交由管道处理
            book = ScrapyDushuItem(name=name, src=src)
            yield book
image-20250123110949980

http://www.kler.cn/a/518688.html

相关文章:

  • wangEditor富文本编辑器,Laravel上传图片配置和使用
  • Kimi 1.5解读:国产AI大模型的创新突破与多模态推理能力(内含论文地址)
  • 在 Vue 项目中快速引入和使用 ECharts
  • Golang 中除了加锁还有哪些安全读写共享变量的方式?
  • 计算机网络-运输层
  • Golang笔记——GPM调度器
  • 《探秘鸿蒙Next:人工智能助力元宇宙高效渲染新征程》
  • vue2和vue3组件之间的通信方式差异
  • 【C++】特殊类设计、单例模式与类型转换
  • 探秘数据仓库新势力:网络建模
  • 基于微信的原创音乐小程序的设计与实现(LW+源码+讲解)
  • 机器人SLAM建图与自主导航
  • 2025年美赛数学建模B题管理可持续旅游
  • vue3中自定一个组件并且能够用v-model对自定义组件进行数据的双向绑定
  • 如何有效利用数据采集HTTP代理
  • ASP.NET代码审计 SQL注入篇(简单记录)
  • 2024年终总结:技术成长与突破之路
  • CCF开源发展委员会开源供应链安全工作组2025年第1期技术研讨会顺利举行
  • FastDFS的安装及使用
  • LabVIEW心音心电同步采集与实时播放