51Testing软件测试论坛

标题: Python爬虫框架Scrapy入门与实践之爬取豆瓣电影Top250榜单 [打印本页]

作者: 八戒你干嘛    时间: 2019-6-17 17:36
标题: Python爬虫框架Scrapy入门与实践之爬取豆瓣电影Top250榜单
什么是爬虫?
网络爬虫(又被称为网页蜘蛛,网络机器人,在 FOAF 社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
其实通俗的讲就是通过程序去获取 web 页面上自己想要的数据,也就是自动抓取数据
爬虫可以做什么?
你可以爬去妹子的图片,爬取自己想看看的视频。。等等你想要爬取的数据,只要你能通过浏览器访问的数据都可以通过爬虫获取
爬虫的本质是什么?
模拟浏览器打开网页,获取网页中我们想要的那部分数据
浏览器打开网页的过程:
当你在浏览器中输入地址后,经过 DNS 服务器找到服务器主机,向服务器发送一个请求,服务器经过解析后发送给用户浏览器结果,包括 html,js,css 等文件内容,浏览器解析出来最后呈现给用户在浏览器上看到的结果
所以用户看到的浏览器的结果就是由 HTML 代码构成的,我们爬虫就是为了获取这些内容,通过分析和过滤 html 代码,从中获取我们想要资源(文本,图片,视频.....)


Python爬虫的原理爬虫的基本流程发起请求
通过 HTTP 库向目标站点发起请求,也就是发送一个 Request,请求可以包含额外的 header 等信息,等待服务器响应
获取响应内容
如果服务器能正常响应,会得到一个 Response,Response 的内容便是所要获取的页面内容,类型可能是 HTML,Json 字符串,二进制数据(图片或者视频)等类型
解析内容
得到的内容可能是 HTML, 可以用正则表达式,页面解析库进行解析,可能是 Json, 可以直接转换为 Json 对象解析,可能是二进制数据,可以做保存或者进一步的处理
保存数据
保存形式多样,可以存为文本,也可以保存到数据库,或者保存特定格式的文件


什么是 Request,Response浏览器发送消息给网址所在的服务器,这个过程就叫做 HTPP Request
服务器收到浏览器发送的消息后,能够根据浏览器发送消息的内容,做相应的处理,然后把消息回传给浏览器,这个过程就是 HTTP Response
浏览器收到服务器的 Response 信息后,会对信息进行相应的处理,然后展示
Request 中包含什么?
请求方式
主要有:GET/POST 两种类型常用,另外还有 HEAD/PUT/DELETE/OPTIONS
GET 和 POST 的区别就是:请求的数据 GET 是在 url 中,POST 则是存放在头部
GET: 向指定的资源发出 “显示” 请求。使用 GET 方法应该只用在读取数据,而不应当被用于产生 “副作用” 的操作中,例如在 Web Application 中。其中一个原因是 GET 可能会被网络蜘蛛等随意访问
POST: 向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。
HEAD:与 GET 方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中 “关于该资源的信息”(元信息或称元数据)。
PUT:向指定资源位置上传其最新内容。
OPTIONS:这个方法可使服务器传回该资源所支持的所有 HTTP 请求方法。用 '*' 来代替资源名称,向 Web 服务器发送 OPTIONS 请求,可以测试服务器功能是否正常运作。
DELETE:请求服务器删除 Request-URI 所标识的资源。
请求 URL
URL,即统一资源定位符,也就是我们说的网址,统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL 的格式由三个部分组成:
第一部分是协议 (或称为服务方式)。
第二部分是存有该资源的主机 IP 地址 (有时也包括端口号)。
第三部分是主机资源的具体地址,如目录和文件名等。
爬虫爬取数据时必须要有一个目标的 URL 才可以获取数据,因此,它是爬虫获取数据的基本依据。
请求头
包含请求时的头部信息,如 User-Agent,Host,Cookies 等信息
请求体
请求是携带的数据,如提交表单数据时候的表单数据(POST)
Response 中包含了什么
所有 HTTP 响应的第一行都是状态行,依次是当前 HTTP 版本号,3 位数字组成的状态代码,以及描述状态的短语,彼此由空格分隔。
响应状态
有多种响应状态,如:200 代表成功,301 跳转,404 找不到页面,502 服务器错误
1xx 消息 —— 请求已被服务器接收,继续处理
2xx 成功 —— 请求已成功被服务器接收、理解、并接受
3xx 重定向 —— 需要后续操作才能完成这一请求
4xx 请求错误 —— 请求含有词法错误或者无法被执行
5xx 服务器错误 —— 服务器在处理某个正确请求时发生错误

常见代码:
200 OK 请求成功
301 目标永久性转移
302 目标暂时性转移
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
401 Unauthorized 请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务
404 Not Found 请求资源不存在,eg:输入了错误的 URL
500 Internal Server Error 服务器发生不可预期的错误
503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间后可能恢复正常

响应头
如内容类型,类型的长度,服务器信息,设置 Cookie
响应体
最主要的部分,包含请求资源的内容,如网页 HTMl, 图片,二进制数据等
能爬取什么样的数据网页文本:如 HTML 文档,Json 格式化文本等
图片:获取到的是二进制文件,保存为图片格式
视频:同样是二进制文件
其他:只要请求到的,都可以获取
如何解析数据直接处理
Json 解析
正则表达式处理
BeautifulSoup 解析处理
PyQuery 解析处理
XPath 解析处理
关于抓取的页面数据和浏览器里看到的不一样的问题出现这种情况是因为,很多网站中的数据都是通过 js,ajax 动态加载的,所以直接通过 get 请求获取的页面和浏览器显示的不同。
如何解决 js 渲染的问题?
分析 ajax
Selenium/webdriver
Splash
PyV8,Ghost.py
怎样保存数据文本:纯文本,Json,Xml 等
关系型数据库:如 mysql,oracle,sql server 等结构化数据库
非关系型数据库:MongoDB,Redis 等 key-value 形式存储
Scrapy简介Scrapy is an application framework for crawling web sites and extracting structured data which can be used for a wide range of useful applications, like data mining, information processing or historical archival.
Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
Scrapy Tutorial
https://docs.scrapy.org/en/latest/intro/overview.html

Scrapy Engine
引擎负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。 详细内容查看下面的数据流 (Data Flow) 部分。
此组件相当于爬虫的 “大脑”,是整个爬虫的调度中心。
调度器 (Scheduler)
调度器从引擎接受 request 并将他们入队,以便之后引擎请求他们时提供给引擎。
初始的爬取 URL 和后续在页面中获取的待爬取的 URL 将放入调度器中,等待爬取。同时调度器会自动去除重复的 URL(如果特定的 URL 不需要去重也可以通过设置实现,如 post 请求的 URL)
下载器 (Downloader)
下载器负责获取页面数据并提供给引擎,而后提供给 spider。
Spiders
Spider 是 Scrapy 用户编写用于分析 response 并提取 item (即获取到的 item) 或额外跟进的 URL 的类。 每个 spider 负责处理一个特定 (或一些) 网站。
Item Pipeline
Item Pipeline 负责处理被 spider 提取出来的 item。典型的处理有清理、 验证及持久化 (例如存取到数据库中)。
当页面被爬虫解析所需的数据存入 Item 后,将被发送到项目管道 (Pipeline),并经过几个特定的次序处理数据,最后存入本地文件或存入数据库。
下载器中间件 (Downloader middlewares)
下载器中间件是在引擎及下载器之间的特定钩子 (specific hook),处理 Downloader 传递给引擎的 response。 其提供了一个简便的机制,通过插入自定义代码来扩展 Scrapy 功能。
通过设置下载器中间件可以实现爬虫自动更换 user-agent、IP 等功能。
Spider 中间件 (Spider middlewares)
Spider 中间件是在引擎及 Spider 之间的特定钩子 (specific hook),处理 spider 的输入 (response) 和输出 (items 及 requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展 Scrapy 功能。
数据流 (Data flow)



作者: 八戒你干嘛    时间: 2019-6-17 17:42
Scrapy 爬取豆瓣电影 Top250 榜单https://docs.scrapy.org/en/latest/intro/tutorial.html
工具和环境
创建项目在开始爬取之前,首先要创建一个新的 Scrapy 项目。这里以爬取豆瓣电影 Top250 为例,进入你打算存储代码的目录中,运行下列命令:

  1. scrapy startproject douban
复制代码
该命令将会创建包含下列内容的 douban 目录:
  1. douban
  2. |-- __init__.py
  3. |-- __pycache__
  4. |   |-- __init__.cpython-37.pyc
  5. |   |-- items.cpython-37.pyc
  6. |   |-- pipelines.cpython-37.pyc
  7. |   `-- settings.cpython-37.pyc
  8. |-- items.py
  9. |-- middlewares.py
  10. |-- pipelines.py
  11. |-- settings.py
  12. `-- spiders
  13.       |-- __init__.py
  14.       |-- __pycache__
  15.       |   |-- __init__.cpython-37.pyc
  16.       |   `-- douban_spider.cpython-37.pyc
  17.       `-- douban_spider.py

  18. 3 directories, 13 files
复制代码
这些文件分别是:
观察页面结构首先我们打开豆瓣电影 TOP250 的页面,通过观察页面决定让我们的爬虫获取每一部电影的排名、电影名称、评分和评分的人数。
https://movie.douban.com/top250
运行Chrome F12开发者工具,使用选取工具选取整个电影的信息,可以发现,所有的信息都是放在单独的一个 li 标签中的,而且在 li 下还有一个 class 为 item 的 div 包裹着所有的信息。

  1. <li>
  2.             <div class="item">
  3.                 <div class="pic">
  4.                     <em class="">1</em>
  5.                     <a href="https://movie.douban.com/subject/1292052/">
  6.                         <img width="100" alt="肖申克的救赎" src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
  7.                     </a>
  8.                 </div>
  9.                 <div class="info">
  10.                     <div class="hd">
  11.                         <a href="https://movie.douban.com/subject/1292052/" class="">
  12.                             <span class="title"> 肖申克的救赎</span>
  13.                                     <span class="title"> / The Shawshank Redemption</span>
  14.                                 <span class="other"> / 月黑高飞 (港)  /  刺激 1995 (台)</span>
  15.                         </a>


  16.                             <span class="playable">[可播放]</span>
  17.                     </div>
  18.                     <div class="bd">
  19.                         <p class="">
  20.                             导演:弗兰克・德拉邦特 Frank Darabont   主演:蒂姆・罗宾斯 Tim Robbins /...<br>
  21.                             1994 / 美国 / 犯罪 剧情
  22.                         </p>

  23.                         
  24.                         <div class="star">
  25.                                 <span class="rating5-t"></span>
  26.                                 <span class="rating_num" property="v:average">9.6</span>
  27.                                 <span property="v:best" content="10.0"></span>
  28.                                 <span>1338863 人评价</span>
  29.                         </div>

  30.                             <p class="quote">
  31.                                 <span class="inq">希望让人自由。</span>
  32.                             </p>
  33.                     </div>
  34.                 </div>
  35.             </div>
  36.         </li>
复制代码
声明Item什么是 Items 呢?官方文档 Items 定义如下:
爬取的主要目标就是从非结构性的数据源提取结构性数据,例如网页。 Scrapy spider 可以以 python 的 dict 来返回提取的数据。虽然 dict 很方便,并且用起来也熟悉,但是其缺少结构性,容易打错字段的名字或者返回不一致的数据,尤其在具有多个 spider 的大项目中。
为了定义常用的输出数据,Scrapy 提供了 Item 类。 Item 对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典 (dictionary-like) 的 API 以及用于声明可用字段的简单语法。
许多 Scrapy 组件使用了 Item 提供的额外信息: exporter 根据 Item 声明的字段来导出数据、 序列化可以通过 Item 字段的元数据 (metadata) 来定义、 trackref 追踪 Item 实例来帮助寻找内存泄露 (see 使用 trackref 调试内存泄露) 等等。
Item 使用简单的 class 定义语法以及 Field 对象来声明。我们打开 spider 目录下的 items.py 文件写入下列代码声明 Item:

  1. # -*- coding: utf-8 -*-

  2. # Define here the models for your scraped items
  3. #
  4. # See documentation in:
  5. # https://doc.scrapy.org/en/latest/topics/items.html

  6. import scrapy

  7. class DoubanItem(scrapy.Item):
  8.     # define the fields for your item here like:
  9.     # name = scrapy.Field()
  10.     serial_number = scrapy.Field()
  11.     movie_name = scrapy.Field()
  12.     introduce = scrapy.Field()
  13.     star = scrapy.Field()
  14.     evaluate = scrapy.Field()
  15.     describe = scrapy.Field()
复制代码
编写爬虫程序
在编写代码前我们可以通过修改settings.py文件调整user-agent和其它参数
  1. # -*- coding: utf-8 -*-

  2. # Scrapy settings for douban project
  3. #
  4. # For simplicity, this file contains only settings considered important or
  5. # commonly used. You can find more settings consulting the documentation:
  6. #
  7. #     https://doc.scrapy.org/en/latest/topics/settings.html
  8. #     https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
  9. #     https://doc.scrapy.org/en/latest/topics/spider-middleware.html

  10. BOT_NAME = 'douban'

  11. SPIDER_MODULES = ['douban.spiders']
  12. NEWSPIDER_MODULE = 'douban.spiders'


  13. # Crawl responsibly by identifying yourself (and your website) on the user-agent
  14. USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'

  15. # Obey robots.txt rules
  16. ROBOTSTXT_OBEY = False

  17. # Configure a delay for requests for the same website (default: 0)
  18. # See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
  19. # See also autothrottle settings and docs
  20. DOWNLOAD_DELAY = 0.5

  21. # Configure item pipelines
  22. # See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
  23. ITEM_PIPELINES = {
  24.    'douban.pipelines.DoubanPipeline': 300,
  25. }

  26. mongo_host = '127.0.0.1'
  27. mongo_port = 27017
  28. mongo_db_name = 'douban'
  29. mongo_db_collection = 'douban_movie'
复制代码
在 spiders 文件夹下创建 douban_spider.py 文件
在我们编写爬虫之前,先了解一下 scrapy 的爬取机制,scrapy 提取数据有自己的一套机制。它们被称作选择器 (seletors),因为他们通过特定的 XPath 或者 CSS 表达式来 “选择” HTML 文件中的某个部分。
Xpath 学习教程
http://www.w3school.com.cn/xpath/index.asp
XPath Helper
https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl
Scrapy xpath-tutorial
https://doc.scrapy.org/en/xpath-tutorial/topics/xpath-tutorial.html

  1. # -*- coding: utf-8 -*-
  2. import scrapy
  3. from douban.items import DoubanItem

  4. class DoubanSpiderSpider(scrapy.Spider):
  5.     name = 'douban_spider'
  6.     allowed_domains = ['movie.douban.com']
  7.     start_urls = ['https://movie.douban.com/top250']

  8.     def parse(self, response):
  9.         movie_list = response.xpath("//div[@class='article']//ol[@class='grid_view']/li")
  10.         for i_item in movie_list:
  11.             douban_item = DoubanItem()
  12.             douban_item['serial_number'] = i_item.xpath(".//div[@class='item']//em/text()").extract_first()
  13.             douban_item['movie_name'] = i_item.xpath(".//div[@class='info']/div[@class='hd']/a/span[1]/text()").extract_first()
  14.             content = i_item.xpath(".//div[@class='info']//div[@class='bd']/p[1]/text()").extract()
  15.             for i_content in content:
  16.                 content_s = "".join(i_content.split())
  17.                 douban_item['introduce'] = content_s
  18.             douban_item['star'] =  i_item.xpath(".//span[@class='rating_num']/text()").extract_first()
  19.             douban_item['evaluate'] = i_item.xpath(".//div[@class='star']//span[4]/text()").extract_first()
  20.             douban_item['describe'] = i_item.xpath(".//p[@class='quote']//span/text()").extract_first()
  21.             yield douban_item
  22.         next_link = response.xpath("//span[@class='next']/link/@href").extract()
  23.         if next_link:
  24.             next_link = next_link[0]
  25.             yield scrapy.Request("https://movie.douban.com/top250"+next_link,callback=self.parse)


复制代码
自动翻页
先别急着高兴,你难道没有发现一个问题吗?这样的话我们还是只能爬到当前页的 25 个电影的内容。怎么样才能把剩下的也一起爬下来呢?
实现自动翻页一般有两种方法:
一般情况下我们使用第一种方法,第二种方法适用于页面的下一页地址为 JS 加载的情况。这次我们只说第一种方法。
首先利用 Chrome 浏览器的开发者工具找到下一页的地址,然后在解析该页面时获取下一页的地址并将地址交给调度器 (Scheduler)









作者: Miss_love    时间: 2020-12-30 15:12
支持分享




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2