python-Scrapy入门

什么是爬虫

网络爬虫(Web Crawler或Spider)是一种自动化程序,通过互联网上的链接遍历并收集特定信息。通常,网络爬虫被用于从互联网上获取大量数据,例如从搜索引擎上抓取网页内容,或者从社交媒体平台上收集用户数据等。

网络爬虫能够模拟人类的浏览器行为,向目标服务器发送请求,并将响应解析成结构化数据。它们会根据预设规则和算法进行自动化抓取,同时能够处理正则表达式、解析HTML/XML格式文本等。收集到的数据可以进行分析、处理、存储等后续操作。

网络爬虫广泛应用于各个领域,包括搜索引擎、电商价格监控、舆情分析、金融市场研究等。

为什么要用python

实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫。

Python 作为一种高级编程语言,在爬虫领域具有诸多优势,包括:

  • 语法简单、易于学习:Python 语法简洁明了,容易理解,对新手友好。即便没有编程经验也能快速上手。

  • 社区活跃:Python 有庞大的社区支持,开发者可以通过在线文档、博客等方式获取相关技术资料和帮助。

  • 丰富的第三方库:Python 有许多强大并且成熟的爬虫库,如 Scrapy、BeautifulSoup、Requests 等,可供使用。

  • 跨平台:Python 可以在多种操作系统上运行,并且与其他编程语言兼容性良好,使得爬虫开发更加灵活。

  • 处理文本数据能力强:爬虫需要处理大量的文本数据,Python 在文本处理方面有着非常出色的表现,如字符串处理、正则表达式等。

  • 支持异步编程:Python 异步编程模型 asyncio,可避免网络请求阻塞,提高爬虫效率。

综上,Python 具有易学易用、社区活跃、丰富的第三方库、跨平台、处理文本数据能力强、支持异步编程等特点,使其成为非常适合做爬虫的编程语言。

为什么要用python爬虫框架

使用Python爬虫框架的好处包括:

  1. 自动化:使用框架可以轻松地编写自动化程序,用于抓取数据并存储为结构化数据。

  2. 快速开发:Python爬虫框架提供了开箱即用的功能和方法,使得开发爬虫变得更快捷和高效。

  3. 爬取效率高:爬虫框架针对不同的网站都有相应的优化策略,使得爬取效率得到了很大的提升,从而也加快了数据采集的速度。

  4. 数据处理:爬虫框架同样提供了一些数据处理的方法,例如:去重、清洗、解析等。这些功能可以让我们更容易地处理爬取到的数据。

  5. 可维护性强:使用Python爬虫框架可以使代码更加模块化,使得代码结构更加清晰,便于日后的维护。

什么是Scrapy

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。它是很强大的爬虫框架,可以满足简单的页面爬取,比如可以明确获知url pattern的情况。它的特性有:HTML, XML源数据 选择及提取 的内置支持;提供了一系列在spider之间共享的可复用的过滤器(即 Item Loaders),对智能处理爬取数据提供了内置支持。

它有以下组件:

  • 引擎 (engine): 该组件控制整个 scrapy 系统的执行流程。主要负责调度其他组件的运作,并掌握其中的数据流。

  • 调度器 (scheduler): 对于爬取任务,Scrapy 使用调度器来安排爬虫执行的顺序。 它接受引擎发出的请求并将其排队,以便在下载器可用时(例如,在等待其他请求或下载完成后)执行请求。

  • 下载器 (downloader): 该组件使 Scrapy 可以从互联网上下载所需内容。它处理引擎通过调度器分配的每个请求,并返回响应。

  • 爬虫 (spiders): 爬虫是 Scrapy 中最重要的组件之一,它定义了如何爬取特定网站的数据。对于每个要爬取的网站,都需要编写一个自定义的 spider。当 Spider 接收到 Response 作为输入时,它将解析网站并提取所需的数据。

  • 项目管道 (pipelines): 一旦数据被从 Spider 提取出来,可以将其传递给项目管道进行处理。管道是 Scrapy 中的一个可扩展组件,使用户能够将数据存储在数据库中、将其转换为 JSON 或 XML 格式等。

  • 下载器中间件 (Downloader Middleware): 下载器中间件是一些钩子函数,可以介入 Scrapy 的下载器处理流程。例如,可以使用这些中间件来为每个请求添加代理、更改 User-Agent 等。

  • Spider 中间件 (Spider Middleware): Spider 中间件同样是一些钩子函数,可以介入 Scrapy 的爬虫处理流程。例如,可以使用这些中间件来对 Spider 输出的数据进行处理、监控爬虫运行情况等。

以上这些组件构成了 Scrapy 框架的主要建筑模块。通过它们的协作,Scrapy 可以实现高效、稳定的网站爬取。

开始自己的第一个Spider

创建项目

在开始抓取之前,必须设置一个新的 Scrapy 项目。输入您要存储代码的目录并运行:

首先在命令行创建Scrapy项目:

scrapy startproject myproject

这将会在当前目录下创建一个名为myproject的文件夹,里面包含以下文件:

myproject/
    scrapy.cfg            # 项目配置文件
    myproject/            # Python模块,主要工作区域
        __init__.py
        items.py          # 定义数据模型
        middlewares.py    # 中间件
        pipelines.py      # 数据处理管道
        settings.py       # 项目配置文件
        spiders/          # 爬虫文件夹
            __init__.py

接下来,我们在spiders文件夹中创建一个新的爬虫文件example.py,内容如下:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["example.com"]
    start_urls = [
        "http://www.example.com",
    ]
    for url in urls:
        yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        filename = "example.html"
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log("Saved file %s" % filename)

以上代码定义了一个名为example的爬虫,它会从http://www.example.com开始抓取数据,并将响应保存到example.html文件中。
Spider 子类化scrapy.Spider 并定义了一些属性和方法:

  • name: 标识scrapy。在一个项目中必须是唯一的,即不能为不同的Spiders设置相同的名称。
  • start_requests(): 必须返回一个可迭代的请求(你可以返回一个请求列表或编写一个生成器函数),scrapy将从中开始爬行。后续请求将从这些初始请求中依次生成。
  • parse():将被调用以处理为每个请求下载的响应的方法。response 参数是 的一个实例TextResponse,它保存页面内容并有更多有用的方法来处理它。

parse()方法通常解析响应,将抓取的数据提取为字典,并找到要遵循的新 URL 并Request从中创建新请求 ()。

如何运行我们的scrapy

要让我们的scrapy工作,请转到项目的顶级目录并运行:

scrapy crawl example

quotes此命令使用我们刚刚添加的名称运行蜘蛛,它将发送一些对example.com域的请求。您将获得类似于此的输出:

... (omitted for brevity)
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Spider opened
2016-12-16 21:24:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:24:05 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (404) <GET http://www.example.com/robots.txt> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://www.example.com> (referer: None)
2016-12-16 21:24:05 [quotes] DEBUG: Saved file example.html
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Closing spider (finished)
...

现在,检查当前目录中的文件。您应该注意到已经创建了一个新文件:example.html,其中包含相应 URL 的内容,正如我们的parse方法所指示的那样。

幕后发生了什么

Scrapy调度Spider的方法scrapy.Request返回的对象。start_requests在收到每个响应后,它实例化Response对象并调用与请求关联的回调方法(在本例中为方法 parse),将响应作为参数传递。

怎么提取数据

Python Scrapy提取数据有多种方式,以下是其中的一些:

  1. XPath选择器:XPath是一种用于从HTML或XML文档中提取数据的语言。Scrapy使用XPath选择器来查找和提取HTML或XML文档中的数据。

  2. CSS选择器:CSS选择器也可以用来从HTML文档中提取数据。Scrapy使用CSS选择器来查找和提取HTML文档中的数据。

  3. 正则表达式:正则表达式可以用来从文本中提取数据。Scrapy可以使用正则表达式来查找和提取HTML文档中的数据。

  4. Item Loaders:Item Loaders是Scrapy中的一个实用工具,它可以将数据提取逻辑从Spider内部移动到单独的类中,并允许您定义如何处理、清理和验证数据。

  5. JsonPath:JsonPath是一种用于从JSON文档中提取数据的语言。如果您正在爬取JSON API,则可以使用JsonPath来提取数据。

这些都是Python Scrapy提取数据的常见方式,开发者可以根据实际需求选择最合适的方式。

XPath

XPath是一种基于路径表达式的查询语言,可以定位和选择XML/HTML文档中的节点以及节点集。Scrapy使用XPath选择器来查找和提取HTML或XML文档中的数据。

以下是关于Python XPath的详细介绍及例子:

XPath语法

XPath语法类似于文件系统路径,由斜杠(/)分隔的一系列元素组成,每个元素都描述了一个节点或一组节点。XPath表达式可以包括元素名称、属性名称、通配符和谓词。

  • 元素名称:元素名称指定要选取的节点类型。
  • 属性名称:属性名称用@符号表示,用于选取特定属性值。
  • 通配符:通配符(*)可以匹配任何节点。
  • 谓词:谓词用方括号([])表示,用于筛选满足条件的节点。

以下是一个使用Python的XPath示例:

假设我们有以下HTML代码:

<html>
  <head>
    <title>This is a title</title>
  </head>
  <body>
    <div id="content">
      <h1>Welcome to my website</h1>
      <p class="intro">This is the introduction paragraph.</p>
      <ul>
        <li><a href="http://www.example.com">Link 1</a></li>
        <li><a href="http://www.example.com">Link 2</a></li>
        <li><a href="http://www.example.com">Link 3</a></li>
      </ul>
      <p class="conclusion">This is the conclusion paragraph.</p>
    </div>
  </body>
</html>

要在Python中使用XPath来选择其中的元素,可以使用 lxml 库。例如,如果我们想选取所有链接的文本内容,可以使用以下代码:

from lxml import html

# 将上面的html代码保存到字符串变量page_content中
page_content = '''
<html>
  <head>
    <title>This is a title</title>
  </head>
  <body>
    <div id="content">
      <h1>Welcome to my website</h1>
      <p class="intro">This is the introduction paragraph.</p>
      <ul>
        <li><a href="http://www.example.com">Link 1</a></li>
        <li><a href="http://www.example.com">Link 2</a></li>
        <li><a href="http://www.example.com">Link 3</a></li>
      </ul>
      <p class="conclusion">This is the conclusion paragraph.</p>
    </div>
  </body>
</html>
'''

# 将页面内容解析为HTML对象
tree = html.fromstring(page_content)

# 使用XPath选取所有链接的文本内容
links = tree.xpath('//a/text()')

# 输出结果
print(links)

这将输出以下结果:

['Link 1', 'Link 2', 'Link 3']

在这个例子中,我们使用 lxml 库中的 html 模块来解析页面内容并创建一个HTML对象。然后,我们使用XPath表达式 //a/text() 来选取所有链接的文本内容,并将结果存储在变量 links 中。最后,我们使用 print() 函数输出结果。

CSS选择器

CSS选择器使用基于类名、ID、标签名等属性来匹配并选取元素。Python中有多个库可以使用CSS选择器,例如 BeautifulSouppyquery

下面是一些常见的CSS选择器及其用法:

选择标签元素

选择所有p元素: p

选择类名

选择class为"example"的所有元素: .example

选择ID

选择id为"header"的元素: #header

选择子元素

选择ul元素下所有的li元素: ul li

选择相邻兄弟元素

选择class为"example"的元素后面第一个相邻的div元素: .example + div

选择后代元素

选择div元素内部所有class为"example"的元素: div .example

以下是在Python中使用CSS选择器的示例:

  1. 从HTML页面中提取所有段落文本:
from bs4 import BeautifulSoup

html = """
<html>
<body>
    <h1>这是标题</h1>
    <p class="intro">这是第一个段落。</p>
    <p class="content">这是第二个段落。</p>
</body>
</html>
"""

soup = BeautifulSoup(html, 'html.parser')
paragraphs = soup.select('p')
for paragraph in paragraphs:
    print(paragraph.text)

输出:

这是第一个段落。
这是第二个段落。
  1. 提取具有特定类的元素的属性值:
from bs4 import BeautifulSoup

html = """
<html>
<body>
    <a href="http://www.example.com" class="link">链接</a>
    <a href="http://www.google.com" class="link">谷歌</a>
</body>
</html>
"""

soup = BeautifulSoup(html, 'html.parser')
links = soup.select('.link')
for link in links:
    print(link['href'])

输出:

http://www.example.com
http://www.google.com
  1. 使用层级结构查找元素:
from bs4 import BeautifulSoup

html = """
<html>
<body>
    <div>
        <h2>这是标题</h2>
        <p>这是段落。</p>
    </div>
    <div>
        <h2>这是另一个标题</h2>
        <p>这是另一个段落。</p>
    </div>
</body>
</html>
"""

soup = BeautifulSoup(html, 'html.parser')
divs = soup.select('body > div')
for div in divs:
    print(div.h2.text)
    print(div.p.text)

输出:

这是标题
这是段落。
这是另一个标题
这是另一个段落。

正则表达式

正则表达式是一种用来描述文本模式的语言,常常被用于文本处理、搜索、替换和数据提取等方面。Python是一个非常强大的正则表达式解析工具,内置re模块可以用于执行正则表达式操作。

下面是Python中正则表达式的详细介绍以及示例:

基本语法
  1. 字符匹配
  • 匹配单个字符:使用.表示任意字符
  • 匹配某个特定字符:在正则表达式中写入该字符即可
  • 匹配一组字符:使用[]表示字符集,例如[abc]会匹配a、b或c中的任意一个字符
  • 匹配除了某些特定字符之外的任意字符:使用[^]表示,例如[^abc]会匹配除了a、b、c之外的任意字符
  1. 重复匹配
  • 匹配前一个字符0次或多次:使用*表示
  • 匹配前一个字符1次或多次:使用+表示
  • 匹配前一个字符0次或1次:使用?表示
  • 匹配前一个字符n次:使用{n}表示
  • 匹配前一个字符至少n次:使用{n,}表示
  • 匹配前一个字符n到m次:使用{n,m}表示
  1. 特殊字符
  • 匹配行首:使用^表示
  • 匹配行尾:使用$表示
  • 匹配数字:使用\d表示
  • 匹配非数字:使用\D表示
  • 匹配空白字符:使用\s表示
  • 匹配非空白字符:使用\S表示
  • 匹配字母、数字和下划线:使用\w表示
  • 匹配除了字母、数字和下划线之外的任意字符:使用\W表示

以下是 Python 中的一些正则表达式示例:

  1. 寻找匹配的字符串:
import re

pattern = r"hello"
text = "hello world"

match_obj = re.search(pattern, text)

if match_obj:
    print("Found", match_obj.group())
else:
    print("Not found")

输出:Found hello

  1. 搜索和替换文本中的字符串:
import re

pattern = r"world"
text = "hello world"

new_text = re.sub(pattern, "Python", text)

print(new_text)

输出:hello Python

  1. 匹配多个可能的模式:
import re

pattern = r"cat|dog"
text = "I have a cat and a dog"

matches = re.findall(pattern, text)

print(matches)

输出:['cat', 'dog']

  1. 匹配指定数量的字符:
import re

pattern = r"\d{3}-\d{2}-\d{4}"
text = "My social security number is 123-45-6789"

match_obj = re.search(pattern, text)

if match_obj:
    print("Found", match_obj.group())
else:
    print("Not found")

输出:Found 123-45-6789

Item Loaders

在 Scrapy 中,Item Loaders 可以帮助我们更方便地处理爬取到的数据,并将其存储到 Item 对象中。它是一种支持链式调用的工具,可以在 Item 对象中添加或修改字段值。

Item Loaders 主要有以下几个特点:

可以使用默认值设置,以避免重复编写多个类似的代码;
支持通过输入处理器和输出处理器对数据进行预处理,以确保数据的一致性;
可以使用自定义的表达式(XPath、CSS 等)从爬取到的数据中提取数据;
可以轻松地扩展和定制 Item Loaders 功能。

下面是一个简单的 Python Item Loader 示例,用于从网页中提取数据并加载到 Scrapy 的 Item 中。

import scrapy
from scrapy.loader import ItemLoader
from myproject.items import MyItem

class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = [
        "http://www.example.com",
    ]

    def parse(self, response):
        loader = ItemLoader(item=MyItem(), response=response)
        loader.add_xpath("title", "//title/text()")
        loader.add_xpath("description", "//meta[@name='description']/@content")
        loader.add_value("url", response.url)
        return loader.load_item()

在以上代码中,我们首先导入了 scrapyItemLoader 模块,以及 Scrapy 项目中定义的 MyItem 类。然后,我们定义了一个 Spider 类,该类继承自 scrapy.Spider 类,并定义了爬取的起始 URL。在 parse 方法中,我们创建了一个 ItemLoader 实例,将其与 MyItem 实例关联。然后,我们使用 add_xpath 方法添加了三个属性:titledescriptionurl。最后,我们通过调用 loader.load_item() 将 Item 返回。

要使用此示例,请将代码复制到 Scrapy 项目的 spiders 目录下,并替换 myprojectMyItem 为您的项目名称和定义的 Item 类。然后,运行 Scrapy 爬虫即可。

JsonPath 是一种用于从 JSON 数据结构中提取信息的语言,类似于 XPath 用于 XML。它非常适合在 Python 中使用,因为许多 Python 库都内置了 JsonPath 的支持。

JsonPath

JsonPath 使用路径表达式来定位 JSON 中的元素。这些表达式类似于 Unix 文件系统中使用的路径名。以下是一些常用的 JsonPath 表达式:

  • $ : 根元素
  • @ : 当前节点
  • . : 子节点
  • .. : 子孙节点
  • * : 所有子节点
  • [] : 数组下标或属性名称
  • [,] : 多个下标或属性

下面是一个简单的例子,演示如何使用 JsonPath 在 Python 中解析 JSON 数据:

import json
from jsonpath_ng import parse

# 定义 JSON 数据
data = {
    "name": "Bob",
    "age": 30,
    "email": "bob@example.com",
    "pets": [
        {"name": "Fluffy", "type": "cat"},
        {"name": "Fido", "type": "dog"}
    ]
}

# 将 JSON 转换为字符串
json_str = json.dumps(data)

# 解析 JSON 字符串
json_data = json.loads(json_str)

# 使用 JsonPath 提取数据
name_expr = parse("$.name")
name = name_expr.find(json_data)[0].value
print(f"Name: {name}")

pet_expr = parse("$.pets[1].name")
pet_name = pet_expr.find(json_data)[0].value
print(f"Pet name: {pet_name}")

在以上代码中,我们首先定义了一个 JSON 数据结构。然后,我们将其转换为字符串,并使用 json.loads() 函数将其解析为 Python 对象。接下来,我们使用 parse() 函数创建了两个 JsonPath 表达式:$.name$.pets[1].name。这些表达式分别提取了 name 属性和第二个宠物的名称。

怎么存储数据

存储抓取数据的最简单方法是使用Feed exports,使用以下命令:

scrapy crawl quotes -O quotes.json

这将生成一个quotes.json包含所有已抓取项目的文件,并以JSON序列化。

命令-O行开关覆盖任何现有文件;use -oinstead 将新内容附加到任何现有文件。但是,附加到 JSON 文件会使文件内容无效 JSON。附加到文件时,请考虑使用不同的序列化格式,例如JSON 行:

scrapy crawl quotes -O quotes.json

JSON行格式很有用,因为它类似于流,您可以轻松地向其追加新记录。当你运行两次时,它没有 JSON 的相同问题。此外,由于每条记录都是单独的一行,因此您可以处理大文件而不必将所有内容都放入内存中,有像JQ这样的工具可以在命令行中帮助完成这项工作。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值