Python Scrapy爬虫简单教程
目标确定
本人在做一个前端页面的项目,用到一些电影数据 , 就打算在网上爬取一些数据,之前使用自写的爬虫demo,但效果不太好,而且费时间.所以打算用框架解决.
框架选择Scrapy.
爬取网页:https://www.ygdy8.net/html/gndy/china/index.html
页面分析
打开页面,https://www.ygdy8.net/html/gndy/china/index.html
进入开发者工具查看元素,我们需要电影名与电影分类.这个页面可以满足要求.
我们还需要图片,这个页面里并没有,我们打开一个链接,发现了图片,页面分析结束.
页面分析结束
准备工作
安装 Scrapy 与安装其他 Python 包没有区别,同样使用如下命令来安装:
pip install scrapy
在安装过程中,可能会出现在安装 Twisted 时会提示以下错误:
error:Microsoft Visual C++ 14.0 is required. Get it with “Microsoft Visual C++ Build Tools”:http://landinghub.visualstudio.com/visual-cpp-build-tools
提示上面的错误只是因为 pip 自动下载的 Twisted 安装包有一些缺陷,因此可以先自行下载 Twisted 安装包。进入 www.lfd.uci.edu/~gohlke/pythonlibs/ 站点,在该页面中间查找“Twisted”项目,可以看到如图 1 所示的下载链接。
当前 Twisted 的最新版是 19.2.1,Twisted 为 2.7、3.5、3.6、3.7 等不同版本的 Python 提供了对应的安装包。由于本教程内容主要以 Python 3.6 为主,因此应该下载 Twisted 的 Python 3.6 版本,其中文件名带 win32 的是 32 位版本,而带 win_amd64 的则是 64 位版本,此处还需要根据操作系统的位数选择对应的版本。
在下载了合适的 Twisted 安装包后,会得到一个 Twisted-18.9.0-cp36-cp36m-win_amd64.whl 文件(针对 64 位系统的),该文件就是 Twisted 安装包。
运行如下命令来安装 Twisted 包。
pip install Twisted-19.2.1-cp36-cp36m-win_amd64.whl
在安装过程中会自动检查,如有必要,会自动下载并安装 Twisted 所依赖的第三方包,如 zope.interface、Automat、incremental 等。
在安装完成后,会提示如下安装成功的信息:
Successfully installed Twisted-18.9.0
在成功安装 Twisted 包之后,再次执行 pip install scrapy 命令,即可成功安装 Scrapy。在安装成功后,会显示如下提示信息:
Successfully installed Scrapy-1.6.1
如果后面执行时还是报 No module named win32api 错误 ,请执行.
pip install pypiwin32
scrapy shell
下面将会使用 Scrapy 提供的 shell 调试工具来抓取该页面中的信息。使用如下命令来开启 shell 调试:
scrapy shell https://www.ygdy8.net/html/gndy/china/index.html
运行上面命令,将会看到 Scrapy 并未抓取到页面数据,但有些运用反爬虫的页面会返回了 403 错误,不允许使用 Scrapy“爬取”数据。为了解决这个问题,我们需要让 Scrapy 伪装成浏览器。
我们可以加上浏览器头来伪装浏览器访问.
scrapy shell -s USER_AGENT='Mozilla/5.0' https://www.ygdy8.net/html/gndy/china/index.html
接下来就可以使用 XPath 或 css 选择器来提取我们感兴趣的信息了。
Xpath是一个简单方便的选择器.这里简单的介绍一下它的语法.
表达式 | 作用 |
---|---|
nodename | 匹配此节点的所有内容 |
/ | 匹配根节点 |
// | 匹配任意位置的节点 |
. | 匹配当前节点 |
. . | 匹配父节点 |
@ | 匹配属性 |
典型的,比如可以使用 //div 来匹配页面中任意位置处的 <div…/> 元素,也可以使用 //div/span 来匹配页面中任意位置处的 <div…> 元素内的 <span…/> 子元素。
XPath 还支持“谓词”,就是在节点后增加一个方括号,在方括号内放一个限制表达式对该节点进行限制。
典型的,我们可以使用 //div[@class]来匹配页面中任意位置处、有 class 属性的 <div…/> 元素,也可以使用 //div/span[1] 来匹配页面中任意位置处的 <div…/> 元素内的第一个 <span…/> 子元素;使用 //div/span[last()] 来匹配页面中任意位置处的 <div…/> 元素内的最后一个 <span…/> 子元素;使用 //div/span[last()-1] 来匹配页面中任意位置处的 <div…/> 元素内的倒数第二个 <span…/> 子元素.
string-length(text())!=6
以页面为例
我们发现每个标签内容都在table中 , 所以开头为://table[@class=“tbspan”]
然后依次向下写//table[@class=“tbspan”]/tr/td/b/a
到这里我们发现了两个 <a>
标签我们需要第二个
所以后面写 //table[@class=“tbspan”]/tr/td/b/a[2] 即可获取标签对象
我们可以通过text()方法获取便签內的文本.也可以通过@href获取它的链接地址
输入
response.xpath ('(//table[@class="tbspan"]/tr/td/b/a[2]/text())').extract()
输入
response.xpath ('(//table[@class="tbspan"]/tr/td/b/a[2]@href)').extract()
开始建立scrapy项目
scrapy startproject MovieSpider
在上面命令中,scrapy 是Scrapy 框架提供的命令;startproject 是 scrapy 的子命令,专门用于创建项目;MovieSpider 就是要创建的项目名。
运行结果:
此时在当前目录下就可以看到一个 MovieSpider 目录,该目录就代表 MovieSpider 项目。
查看 MovieSpider 项目,可以看到如下文件结构:
MovieSpider├── MovieSpider│ ├── __init__.py│ ├── items.py│ ├── middlewares.py│ ├── pipelines.py│ ├── __pycache__│ ├── settings.py│ └── spiders│ ├── __init__.py│ └── __pycache__└── scrapy.cfg
下面大致介绍这些目录和文件的作用:
- scrapy.cfg:项目的总配置文件,通常无须修改。
- MovieSpider:项目的 Python 模块,程序将从此处导入 Python 代码。
- MovieSpider/items.py:用于定义项目用到的 Item 类。Item 类就是一个 DTO(数据传输对象),通常就是定义 N 个属性,该类需要由开发者来定义。
- MovieSpider/pipelines.py:项目的管道文件,它负责处理爬取到的信息。该文件需要由开发者编写。
- MovieSpider/settings.py:项目的配置文件,在该文件中进行项目相关配置。
- MovieSpider/spiders:在该目录下存放项目所需的蜘蛛,蜘蛛负责抓取项目感兴趣的信息。
通过前面的 Scrapy shell 调试,已经演示了使用 XPath 从 HTML 文档中提取信息的方法,只要将这些调试的测试代码放在 Spider 中,即可实现真正的 Scrapy 爬虫。
基于 Scrapy 项目开发爬虫大致需要如下几个步骤:
定义 Item 类。该类仅仅用于定义项目需要爬取的 N 个属性。
编辑 items.py
import scrapyclass MoviespiderItem(scrapy.Item):#电影名name = scrapy.Field()#uriuri = scrapy.Field()
上面程序中,第 2 行代码表明所有的 Item 类都需要继承 scrapy.Item 类,接下来就为所有需要爬取的信息定义对应的属性,每个属性都是一个 scrapy.Field 对象。
该 Item 类只是一个作为数据传输对象(DTO)的类,因此定义该类非常简单。
编写 Spider 类
应该将该 Spider 类文件放在 spiders 目录下。这一步是爬虫开发的关键,需要使用 XPath 或 CSS 选择器来提取 HTML 页面中感兴趣的信息。
Scrapy 为创建 Spider 提供了 scrapy genspider 命令,该命令的语法格式如下:
scrapy genspider [options] <name> <domain>
在命令行窗口中进入 ZhipinSpider 目录下,然后执行如下命令即可创建一个 Spider:
scrapy genspider job_position "ygdy8.net"
运行上面命令,即可在 MovieSpider 项目的 MovieSpider/spider 目录下找到一个 job_position.py 文件
编辑job_position.py
import scrapy
from MovieSpider.items import MoviespiderItemclass JobPositionSpider(scrapy.Spider):name = 'job_position'allowed_domains = ['ygdy8.net']#这里写上你要爬取的页面start_urls = ['https://www.ygdy8.net/html/gndy/china/index.html']#爬取的方法def parse(self, response):#注意在上面导入MoviespiderItem包item = MoviespiderItem()#匹配for jobs_primary in response.xpath('//table[@class="tbspan"]'):item['name'] = jobs_primary.xpath ('./tr/td/b/a[2]/text()').extract()item['uri'] = jobs_primary.xpath ('./tr/td/b/a[2]/@href').extract()#不能使用return yield item
修改pipeline类
这个类是对爬取的文件最后的处理,一般为负责将所爬取的数据写入文件或数据库中.
这里我们将它输出到控制台.
class MoviespiderPipeline(object):def process_item(self, item, spider):print("name:",item['name'])print("url:",item['url'])
修改settings类
BOT_NAME = 'MovieSpider'SPIDER_MODULES = ['MovieSpider.spiders']NEWSPIDER_MODULE = 'MovieSpider.spiders'ROBOTSTXT_OBEY = True
# 配置默认的请求头
DEFAULT_REQUEST_HEADERS = {"User-Agent" : "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0",'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}
# 配置使用Pipeline
ITEM_PIPELINES = {'MovieSpider.pipelines.MoviespiderPipeline': 300,
}
一个 Scarpy项目的简单架构就完成了我们可以运行一下试试.
在MovieSpider目录下执行
scrapy crawl job_position
可以看到运行结果
但只有 一页的内容 , 我们可以解析下一页 .
将以下代码加到 job_position.py
new_links = response.xpath('//a[text()="下一页"]/@href').extract()if new_links and len(new_links) > 0:# 获取下一页的链接new_link = new_links[0]# 再次发送请求获取下一页数据yield scrapy.Request("https://www.ygdy8.net/html/gndy/china/" + new_link, callback=self.parse)
job_position.py最终内容
# -*- coding: utf-8 -*-
import scrapy
from MovieSpider.items import MoviespiderItemclass JobPositionSpider(scrapy.Spider):name = 'job_position'allowed_domains = ['ygdy8.net']start_urls = ['https://www.ygdy8.net/html/gndy/china/index.html']def parse(self, response):item = MoviespiderItem()for jobs_primary in response.xpath('//table[@class="tbspan"]'):item['name'] = jobs_primary.xpath ('./tr/td/b/a[2]/text()').extract()item['uri'] = jobs_primary.xpath ('./tr/td/b/a[2]/@href').extract()yield itemnew_links = response.xpath('//a[text()="下一页"]/@href').extract()if new_links and len(new_links) > 0:# 获取下一页的链接new_link = new_links[0]# 再次发送请求获取下一页数据yield scrapy.Request("https://www.ygdy8.net/html/gndy/china/" + new_link, callback=self.parse)
再次执行 , 就会一页一页的爬取 .
进阶
我们可以将爬取到的内入保存到本地.这里使用python的pandas模块
我们只需修改pipeline.py的内容即可
class MoviespiderPipeline(object):def __init__(self):# 定义构造器,初始化要写入的文件self.mypd = pd.DataFrame(columns=['name','uri'])def close_spider(self, spider):#重写close_spider回调方法self.mypd.to_csv("movie.csv")def process_item(self, item, spider):#添加数据到pandas中self.mypd = self.mypd.append({'name':item['name'][0],'uri':item['uri'][0]},ignore_index=True)print(len(self.mypd))
这样就把数据爬取到文件中了, 同理把数据爬取到数据库什么的都是类似的 .
进阶 图片爬取
我们在上面获得了电影名和电影详情的路径 , 接下来只需要将每个详情页面的图片爬取出来.
分析页面:
我们可以很简单的得到图片的路径
我们可以选择保存图片路径用其他下载器下载也可以用自带的图片文件选择器 , 我这里使用自带的下载器.
建立名为 ImageSpider 的Scrapy项目 , 使用自带的下载器需要修改一些内容 所以我们先修改settings .py
settings. py
BOT_NAME = 'ImageSpider'SPIDER_MODULES = ['ImageSpider.spiders']
NEWSPIDER_MODULE = 'ImageSpider.spiders'ROBOTSTXT_OBEY = True
ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1,'scrapy.pipelines.files.FilesPipeline': 2,
}
FILES_STORE = 'D:' # 文件存储路径
IMAGES_STORE = 'D:' # 图片存储路径# 避免下载最近90天已经下载过的文件内容
FILES_EXPIRES = 90
# 避免下载最近90天已经下载过的图像内容
IMAGES_EXPIRES = 30# 设置图片缩略图# 图片过滤器,最小高度和宽度,低于此尺寸不下载
IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110
# 浏览器头
DEFAULT_REQUEST_HEADERS = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en','User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
}IMAGES_STORE='D:\\jiandan'ITEM_PIPELINES = {'ImageSpider.pipelines.ImagespiderPipeline': 300,
}
items. py
mport scrapyclass ImagespiderItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()image_urls = scrapy.Field()#图片的链接images = scrapy.Field()
job_position. py
# -*- coding: utf-8 -*-
import scrapy
import pandas as pdfrom ImageSpider.items import ImagespiderItemclass JobPositionSpider(scrapy.Spider):name = 'job_position'allowed_domains = ['ygdy8.net']start_urls = ['https://www.ygdy8.net/html/gndy/dyzz/20190713/58833.html']def parse(self, response):item = ImagespiderItem()item['image_urls'] = response.xpath ('//p/img[1]/@src').extract()yield item
pipelines. py
import scrapy
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline #内置的图片管道class ImagespiderPipeline(ImagesPipeline):def get_media_requests(self, item, info):for image_url in item['image_urls']:print("图片连接:",image_url)yield scrapy.Request(image_url)def item_completed(self, results, item, info):image_paths = [x['path'] for ok, x in results if ok]if not image_paths:raise DropItem("Item contains no images")return item
- get_media_requests(item, info)
在工作流程中,管道会得到图片的URL并从项目中下载。为了这么做,你需要重写 get_media_requests() 方法,并对各个图片URL返回一个Request
这些请求将被管道处理,当它们完成下载后,结果将以2元素的元组列表形式传送到 item_completed() 方法: 每个元组包含 (success, file_info_or_error):
success 是一个布尔值,当图片成功下载时为 True ,因为某个原因下载失败为False
file_info_or_error 是一个包含下列关键字的字典(如果成功为 True )或者出问题时为 Twisted Failure 。
url - 文件下载的url。这是从 get_media_requests() 方法返回请求的url。
path - 图片存储的路径(类似 IMAGES_STORE)
checksum - 图片内容的 MD5 hash
item_completed() 接收的元组列表需要保证与 get_media_requests() 方法返回请求的顺序相一致。下面是 results 参数的一个典型值:
[(True,
{‘checksum’: ‘2b00042f7481c7b056c4b410d28f33cf’,
‘path’: ‘full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg’,
‘url’: ‘http://www.example.com/files/product1.jpg’}),
(False,
Failure(…))]
该方法 必须返回每一个图片的URL。
- item_completed(results, items, info)
当一个单独项目中的所有图片请求完成时,例如,item里面一共有10个URL,那么当这10个URL全部下载完成以后,ImagesPipeline.item_completed() 方法将被调用。默认情况下, item_completed() 方法返回item。.
总之 , 一个图片爬虫写好了 我们可以运行一下试一试 , 可以在图片保存路径发现图片 .
但这只是一张图片 我们 需要的是刚刚怕下来的movie.csv中全部的图片 ,那只需要修改 job_position. py
import scrapy
import pandas as pdfrom ImageSpider.items import ImagespiderItemclass JobPositionSpider(scrapy.Spider):name = 'job_position'allowed_domains = ['ygdy8.net']start_urls = ['https://www.ygdy8.net/html/gndy/dyzz/20190713/58833.html']#这句话可写可不写 , 没有影响def start_requests(self):#重写这个方法url = pd.read_csv("movie.csv",usecols=["uri"])#读取csv文件,改为你的路径url = url.head(5)#只取前5条数据urls=[x for x in url["uri"]]for url in urls:url='https://www.ygdy8.net/'+urlyield scrapy.Request(url=url, callback=self.parse)def parse(self, response):item = ImagespiderItem()item['image_urls'] = response.xpath ('//p/img[1]/@src').extract()yield item
这样 就完成了整个项目 .
Python Scrapy爬虫简单教程相关推荐
- Python Scrapy 爬虫简单教程
导览 1. Scrapy install 2. Scrapy 项目创建 3. Scrapy 自定义爬虫类 4. Scrapy 处理逻辑 5. Scrapy 扩展 1. Scrapy install 准 ...
- Python网络爬虫简单教程——第一部
Python网络爬虫简单教程--第一部 感谢,如需转载请注明文章出处:https://blog.csdn.net/weixin_44609873/article/details/103384984 P ...
- Python Scrapy爬虫框架实战应用
通过上一节<Python Scrapy爬虫框架详解>的学习,您已经对 Scrapy 框架有了一个初步的认识,比如它的组件构成,配置文件,以及工作流程.本节将通过一个的简单爬虫项目对 Scr ...
- scrapy爬虫框架教程(二)-- 爬取豆瓣电影
前言 经过上一篇教程我们已经大致了解了Scrapy的基本情况,并写了一个简单的小demo.这次我会以爬取豆瓣电影TOP250为例进一步为大家讲解一个完整爬虫的流程. 工具和环境 语言:python 2 ...
- Scrapy爬虫入门教程五 Selectors(选择器)
Scrapy爬虫入门教程一 安装和基本使用 Scrapy爬虫入门教程二 官方提供Demo Scrapy爬虫入门教程三 命令行工具介绍和示例 Scrapy爬虫入门教程四 Spider(爬虫) Scrap ...
- python商业爬虫教程_廖雪峰老师的Python商业爬虫课程 Python网络爬虫实战教程 体会不一样的Python爬虫课程...
廖雪峰老师的Python商业爬虫课程 Python网络爬虫实战教程 体会不一样的Python爬虫课程 1.JPG (53.51 KB, 下载次数: 1) 2019-8-9 08:15 上传 2.JPG ...
- python网络爬虫系列教程_Python网络爬虫系列教程连载 ----长期更新中,敬请关注!...
感谢大家长期对Python爱好者社区的支持,后期Python爱好者社区推出Python网络爬虫系列教程.欢迎大家关注.以下系列教程大纲,欢迎大家补充.视频长期连载更新中 --------------- ...
- Python Scrapy 爬虫 - 爬取多级别的页面
Python Scrapy 爬虫 - 爬取多级别的页面 互联网中众多的 scrapy 教程模板,都是爬取 下一页 → \rightarrow →下一页形式的,很少有 父级 → \rightarrow ...
- Python Scrapy 爬虫框架爬取推特信息及数据持久化!整理了我三天!
最近要做一个国内外新冠疫情的热点信息的收集系统,所以,需要爬取推特上的一些数据,然后做数据分类及情绪分析.作为一名合格的程序员,我们要有「拿来主义精神」,借助别人的轮子来实现自己的项目,而不是从头搭建 ...
- python爱心代码简单教程
python爱心代码简单教程操作方法 1 将以上代码保存为.py文件,假设保存的文件名为 love.py (不会保存?先保存为txt文本,然后将后缀改为.py) 2 在终端(cmd命令窗口)输入pyt ...
最新文章
- python 获取主机名 根据端口杀死进程
- 武大首位女院士逝世,国际再生资源领域最高奖中国第一人,享年80岁
- 数据库连接池DBPool分析(一):简介
- 大厂的 404 页面都长啥样?看到最后一个,我笑了...
- Java基础学习-Path环境变量的配置
- “约见”面试官系列之常见面试题第七篇说说Vue的生命周期(建议收藏)
- html 单行文本(input text)
- 谁爱谁都没有错... ...
- 单片机无线串行接口电路设计
- 盘点13个值得程序员逛的论坛
- Groq:从头设计一个张量流式处理器架构
- 微信语音转文字的体验报告
- excel绁炵粡缃戠粶瀹炵幇,excel 绁炵粡缃戠粶
- Android 麦克风录音动画
- 11.深入浅出:深度负反馈及放大倍数——参考《模拟电子技术基础》清华大学华成英主讲
- IDEA报错 Cannot resolve method ‘xxx‘ in ‘xxx‘
- 《计算机视觉之三维重建》笔记1-数学基础
- 解决get传参有数组问题
- 七牛云存储,不再为网站空间担心
- 关于一般局域网如何应对ARP***
热门文章
- win10无线网 服务器,win10专业版wifi变成地球怎么办_win10 wifi图标变成小地球无法连接网络如何解决...
- HTML页面布局适配不同分辨率
- VTK:线宽用法实战
- 华为机试:VLAN资源池
- 亚马逊防关联方法适合shopee平台吗?
- SpringMVC整合百度富文本编辑器
- 【0723】自动化运维——saltstack
- easyUI的常用API
- 如何更改itunes备份位置_Mac怎么修改iTunes的备份路径 如何在 Mac 中修改iTunes的备份路径...
- 英语好文22.6.23