微网站首页,佛山做企业网站,广西壮族自治区学生资助管理中心,自己做副业可以抢哪个网站Scrapy 是一个用于Python的开源网络爬虫框架#xff0c;它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取#xff0c;如数据挖掘、监控和自动化测试等。
【1】安装
pip install scrapy安装成功如下所示#xff1a;…Scrapy 是一个用于Python的开源网络爬虫框架它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取如数据挖掘、监控和自动化测试等。
【1】安装
pip install scrapy安装成功如下所示 如果安装过程出错可以参考下面步骤解决
# 1 pip install scrapy
# (2) 报错1 building twisted.test.raiser extension
# error: Microsoft Visual C 14.0 is required. Get it with Microsoft Visual C
# Build Tools: http://landinghub.visualstudio.com/visual-cpp-build-tools
# 解决1
# http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
# Twisted‑20.3.0‑cp37‑cp37m‑win_amd64.whl
# cp是你的python版本
# amd是你的操作系统的版本
# 下载完成之后 使用pip install twisted的路径 安装
# 切记安装完twisted 再次安装scrapy# 3 报错2 提示python -m pip install --upgrade pip
# 解决2 运行python -m pip install --upgrade pip# 4 报错3 win32的错误
# 解决3 pip install pypiwin32# 5 anaconda【2】基础入门
scrapy项目的结构
项目名字项目名字spiders文件夹 存储的是爬虫文件init自定义的爬虫文件 核心功能文件 ****************inititems 定义数据结构的地方 爬取的数据都包含哪些middleware 中间件 代理pipelines 管道 用来处理下载的数据settings 配置文件 robots协议 ua定义等创建Scrapy项目
创建一个新的Scrapy项目你可以在命令行中输入以下命令
scrapy startproject myproject这将在当前目录下创建一个名为myproject的新目录其中包含了Scrapy项目的结构。
scrapy startproject jane定义Item
在Scrapy中Item是被用来保存抓取到的数据的容器。你可以定义自己的Item类类似于Python字典但是提供了额外保护机制和便利方法。Item通常定义在items.py文件中。
class ScrapyDangdangItem(scrapy.Item):# define the fields for your item here like:# name scrapy.Field()# 通俗的说就是你要下载的数据都有什么# 图片src scrapy.Field()# 名字name scrapy.Field()# 价格price scrapy.Field()# 详情URLdetail_url scrapy.Field()
编写Spider
创建爬虫文件 要在spiders文件夹中去创建爬虫文件 cd 项目的名字\项目的名字\spiders
scrapy genspider 爬虫文件的名字 要爬取网页# 示例如下
scrapy genspider baidu http://www.baidu.com一般情况下不需要添加http协议 因为start_urls的值是根据allowed_domains修改的 所以添加了http的话 那么start_urls就需要我们手动去修改了
Spiders是定义如何抓取某个或某些网站的类。每个Spider负责处理一个特定的网站或者一组相关的网页。Spiders通常位于spiders目录下并且以.py文件的形式存在。
class BaiduSpider(scrapy.Spider):name baiduallowed_domains [www.baidu.com]start_urls [http://www.baidu.com]# 是执行了start_urls之后 执行的方法 方法中的response 就是返回的那个对象# 相当于 response urllib.request.urlopen()# response requests.get()def parse(self, response):# 可以直接使用xpath或BS4span response.xpath(//div[idfilter]/div[classtabs]/a/span)[0]print()print(span.extract())response的属性和方法
response.text 获取的是响应的字符串
response.body 获取的是二进制数据
response.xpath 可以直接是xpath方法来解析response中的内容
response.extract() 提取seletor对象的data属性值
response.extract_first() 提取的seletor列表的第一个数据管道 (Pipeline)
管道是用来处理由Spider抓取并返回的Items的地方。你可以在pipelines.py中定义如何处理这些Items比如清洗、验证数据或者将它们存储到数据库中。
设置 (Settings)
Scrapy的行为可以通过修改settings.py文件来定制例如设置下载延迟、启用/禁用中间件、更改用户代理等。
运行 Spider
最后你可以通过命令行运行你的Spider
scrapy crawl baidu【3】管道的使用
pipelines管道就是用来处理数据的如数据清洗、处理、校验、修正以及存储。
如果想使用管道的话 那么就必须在settings中开启管道可以定义多个管道通过优先级数值来决定执行次序。
from itemadapter import ItemAdapter
class ScrapyDangdangPipeline:# 在爬虫文件开始的之前就执行的一个方法def open_spider(self,spider):self.fp open(book.json,w,encodingutf-8)# item就是yield后面的book对象def process_item(self, item, spider):# 以下这种模式不推荐 因为每传递过来一个对象 那么就打开一次文件 对文件的操作过于频繁# # (1) write方法必须要写一个字符串 而不能是其他的对象# # (2) w模式 会每一个对象都打开一次文件 覆盖之前的内容# with open(book.json,a,encodingutf-8)as fp:# fp.write(str(item))self.fp.write(str(item))return item# 在爬虫文件执行完之后 执行的方法def close_spider(self,spider):self.fp.close()import urllib.request# 多条管道开启
# (1) 定义管道类
# 2 在settings中开启管道
# scrapy_dangdang_.pipelines.DangDangDownloadPipeline:301
class DangDangDownloadPipeline:def process_item(self, item, spider):url http: item.get(src)filename ./books/ item.get(name) .jpgurllib.request.urlretrieve(url url, filename filename)return itemsettings.py中开启管道
ITEM_PIPELINES {# 管道可以有很多个 那么管道是有优先级的 优先级的范围是1到1000 值越小优先级越高scrapy_dangdang_.pipelines.ScrapyDangdangPipeline: 300,# DangDangDownloadPipelinescrapy_dangdang_.pipelines.DangDangDownloadPipeline:301
}【4】Scrapy中yield的使用
在 Scrapy 中yield 有着特别重要的作用尤其是在 Spider 类中。Scrapy 使用 yield 来返回请求Request和项目Item而不需要将它们全部加载到内存中。这使得 Scrapy 可以高效地处理大量的页面和数据。
在 Scrapy 中yield 主要用于以下两个场景
1. 返回 Request 对象
当您需要从一个页面抓取多个链接并发送请求时可以使用 yield 来逐个返回 Request 对象。Scrapy 会自动处理这些请求并将响应传递给指定的回调函数。
class DangSpider(scrapy.Spider):name dangstart_urls [http://category.dangdang.com/cp01.01.02.00.00.00.html]def parse(self, response):li_list response.xpath(//ul[idcomponent_59]/li)for li in li_list:detail_url http: li.xpath(./a/href).get()if detail_url:yield scrapy.Request(detail_url, callbackself.parse_detail)def parse_detail(self, response):review_count response.xpath(//a[idcomm_num_down]/dd_name).get()if review_count is None:review_count 评论数未找到else:review_count review_count.strip()self.logger.info(f当前图书评论数为: {review_count})在这个例子中parse 方法会遍历列表页中的每个书籍链接并使用 yield 逐个返回 Request 对象。Scrapy 会依次处理这些请求并将详情页的响应传递给 parse_detail 方法。
2. 返回 Item 对象
当您从页面中提取数据并构建 Item 时可以使用 yield 将 Item 返回给 Scrapy 的管道进行进一步处理如保存到数据库、导出为文件等。
class DangSpider(scrapy.Spider):name dangstart_urls [http://category.dangdang.com/cp01.01.02.00.00.00.html]def parse(self, response):li_list response.xpath(//ul[idcomponent_59]/li)for li in li_list:src li.xpath(.//img/data-original).get() or li.xpath(.//img/src).get()name li.xpath(.//img/alt).get()price li.xpath(.//p[classprice]/span[1]/text()).get()detail_url http: li.xpath(./a/href).get()if not src or not name or not price or not detail_url:self.logger.warning(缺少关键信息跳过此条目)continuebook_info {src: src,name: name,price: price,detail_url: detail_url}yield scrapy.Request(detail_url, callbackself.parse_detail, cb_kwargs{book_info: book_info})def parse_detail(self, response, book_info):review_count response.xpath(//a[idcomm_num_down]/dd_name).get()if review_count is None:review_count 评论数未找到else:review_count review_count.strip()book_info[review_count] review_countbook_item ScrapyDangdangItem(**book_info)self.logger.info(f抓取到完整图书信息: {book_item})yield book_item在这个例子中parse_detail 方法会从详情页提取评论数并将其添加到 book_info 字典中。然后它会创建一个 ScrapyDangdangItem 实例并使用 yield 将其返回给 Scrapy 的管道。
【5】parse方法之间如何传参
比如需要先获取分类列表然后获取每一个详情最后整合获取得到book信息。
在 Scrapy 中通常情况下您会希望将从详情页获取的数据如评论数与列表页获取的数据如书名、价格等结合起来形成一个完整的 Item。为了实现这一点您可以使用 Request 的 meta 参数来传递数据或者使用 cb_kwargs 参数Scrapy 1.7来传递关键字参数。
方法 1: 使用 meta 参数
meta 参数允许您在请求之间传递数据。您可以在 parse 方法中将书籍的基本信息如书名、价格、图片链接等通过 meta 传递给 parse_detail 方法然后在 parse_detail 中提取评论数并返回一个完整的 Item。
修改后的代码
import scrapy
from ..items import ScrapyDangdangItem # 确保这里正确导入了Itemclass DangSpider(scrapy.Spider):name dangallowed_domains [dangdang.com] # 放宽域名限制start_urls [http://category.dangdang.com/cp01.01.02.00.00.00.html]base_url http://category.dangdang.com/pgpage 1def parse(self, response):li_list response.xpath(//ul[idcomponent_59]/li)for li in li_list:src li.xpath(.//img/data-original).get() or li.xpath(.//img/src).get()name li.xpath(.//img/alt).get()price li.xpath(.//p[classprice]/span[1]/text()).get()detail_url http: li.xpath(./a/href).get()if not src or not name or not price or not detail_url:self.logger.warning(缺少关键信息跳过此条目)continue# 构建基础的图书信息book_info {src: src,name: name,price: price,detail_url: detail_url}# 发送详情页请求并通过 meta 传递图书信息yield scrapy.Request(detail_url, callbackself.parse_detail, meta{book_info: book_info})def parse_detail(self, response):# 从 meta 中获取图书信息book_info response.meta[book_info]# 提取评论数review_count response.xpath(//a[idcomm_num_down]/dd_name).get()if review_count is None:review_count 评论数未找到else:review_count review_count.strip()# 将评论数添加到图书信息中book_info[review_count] review_count# 创建并返回完整的 Itembook_item ScrapyDangdangItem(**book_info)self.logger.info(f抓取到完整图书信息: {book_item})yield book_item方法 2: 使用 cb_kwargs 参数 (Scrapy 1.7)
cb_kwargs 是 Scrapy 1.7 版本引入的一个新特性它允许您直接在 Request 中传递关键字参数而不需要通过 meta。这种方式更加直观和简洁。
修改后的代码
import scrapy
from ..items import ScrapyDangdangItem # 确保这里正确导入了Itemclass DangSpider(scrapy.Spider):name dangallowed_domains [dangdang.com] # 放宽域名限制start_urls [http://category.dangdang.com/cp01.01.02.00.00.00.html]base_url http://category.dangdang.com/pgpage 1def parse(self, response):li_list response.xpath(//ul[idcomponent_59]/li)for li in li_list:src li.xpath(.//img/data-original).get() or li.xpath(.//img/src).get()name li.xpath(.//img/alt).get()price li.xpath(.//p[classprice]/span[1]/text()).get()detail_url http: li.xpath(./a/href).get()if not src or not name or not price or not detail_url:self.logger.warning(缺少关键信息跳过此条目)continue# 构建基础的图书信息book_info {src: src,name: name,price: price,detail_url: detail_url}# 发送详情页请求并通过 cb_kwargs 传递图书信息yield scrapy.Request(detail_url, callbackself.parse_detail, cb_kwargs{book_info: book_info})def parse_detail(self, response, book_info):# 提取评论数review_count response.xpath(//a[idcomm_num_down]/dd_name).get()if review_count is None:review_count 评论数未找到else:review_count review_count.strip()# 将评论数添加到图书信息中book_info[review_count] review_count# 创建并返回完整的 Itembook_item ScrapyDangdangItem(**book_info)self.logger.info(f抓取到完整图书信息: {book_item})yield book_item关键点解释 meta 参数 在 parse 方法中我们构建了一个包含图书基本信息的字典 book_info。使用 meta 参数将 book_info 传递给 parse_detail 方法。在 parse_detail 中通过 response.meta[book_info] 获取传递过来的图书信息。 cb_kwargs 参数 在 parse 方法中我们同样构建了一个包含图书基本信息的字典 book_info。使用 cb_kwargs 参数将 book_info 作为关键字参数传递给 parse_detail 方法。在 parse_detail 中直接通过函数参数 book_info 获取传递过来的图书信息。 合并数据 在 parse_detail 中我们提取了评论数并将其添加到 book_info 字典中。最后我们创建了一个 ScrapyDangdangItem 实例并将其返回给 Scrapy 的管道进行处理。
【6】管道中使用pymysql存储数据
from itemadapter import ItemAdapterclass ScrapyReadbookPipeline:def open_spider(self,spider):self.fp open(book.json,w,encodingutf-8)def process_item(self, item, spider):self.fp.write(str(item))return itemdef close_spider(self,spider):self.fp.close()# 加载settings文件
from scrapy.utils.project import get_project_settings
import pymysqlclass MysqlPipeline:def open_spider(self,spider):settings get_project_settings()self.host settings[DB_HOST]self.port settings[DB_PORT]self.user settings[DB_USER]self.password settings[DB_PASSWROD]self.name settings[DB_NAME]self.charset settings[DB_CHARSET]self.connect()def connect(self):self.conn pymysql.connect(hostself.host,portself.port,userself.user,passwordself.password,dbself.name,charsetself.charset)self.cursor self.conn.cursor()def process_item(self, item, spider):sql insert into book(name,src) values({},{}).format(item[name],item[src])# 执行sql语句self.cursor.execute(sql)# 提交self.conn.commit()return itemdef close_spider(self,spider):self.cursor.close()self.conn.close()
数据库配置信息在settings.py中 【7】日志级别与存储路径
settings.py中配置日志级别与路径即可
# 指定日志的级别
# LOG_LEVELWARNINGLOG_FILE logdemo.log【8】POST请求
如下所示是GET请求
yield scrapy.Request(urldetail_url, callbackself.parse_detail)重写start_requests方法使用FormRequest发送POST请求
class TestpostSpider(scrapy.Spider):name testpostallowed_domains [https://fanyi.baidu.com/sug]# post请求 如果没有参数 那么这个请求将没有任何意义# 所以start_urls 也没有用了# parse方法也没有用了# start_urls [https://fanyi.baidu.com/sug/]## def parse(self, response):# passdef start_requests(self):url https://fanyi.baidu.com/sugdata {kw: final}yield scrapy.FormRequest(urlurl,formdatadata,callbackself.parse_second)def parse_second(self,response):content response.textobj json.loads(content,encodingutf-8)print(obj)【9】与xpath结合使用
如下图所示想要提取week内容
dl_weather response.xpath(//dl[classweather_info])
dl_weather_xpath dl_weather.xpath(//dd[classweek])
# 这里获取的是Selector 数组data为目标html 元素
print(dl_weather.xpath(//dd[classweek\]), dl_weather_xpath) # 这里获取的是Selector 数组data为目标html 元素的文本内容
weather_xpath dl_weather.xpath(//dd[classweek]/text())
print(dl_weather.xpath(//dd[classweek\]/text()), weather_xpath)# 这里获取的是文本数组
week__extract weather_xpath.extract()# extract_first表示获取第一个文本节点
print(weather_xpath.extract_first() :,weather_xpath.extract_first())print(weather_xpath.extract() :,week__extract)结果如下所示
dl_weather.xpath(//dd[classweek]) [Selector query//dd[classweek] datadd classweek2024年12月16日\u3000星期一\u3000甲辰年冬...]dl_weather.xpath(//dd[classweek]/text()) [Selector query//dd[classweek]/text() data2024年12月16日\u3000星期一\u3000甲辰年冬月十六 ]
weather_xpath.extract_first() : 2024年12月16日 星期一 甲辰年冬月十六
weather_xpath.extract() : [2024年12月16日\u3000星期一\u3000甲辰年冬月十六 ]
{date: [2024年12月16日\u3000星期一\u3000甲辰年冬月十六 ]}