1. 网络爬虫原理
互联网上大量的信息以网页形式提供给用户,用户通过浏览器从服务器获得网页数据并经过浏览器解析后,进行网页阅读、内容复制、链接单击等操作。用户与网页服务器的通信是通过HTTP或者HTTPS实现的,网络浏览器是用户向服务器发送请求数据、接收服务器回应数据、解析并呈现服务器回应数据的客户端软件。
用户不通过浏览器而是通过程序自动获取网页内容,有两种办法:一是当服务器提供API方法时,可以调用API获取网页数据;二是当服务器没有提供API方法时,需要使用爬虫程序从服务器获取网页数据并从中过滤提取所需数据。
2. Scrapy框架
Scrapy是适用于Python的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
2.1 框架结构
2.2 执行流程
- 爬虫(Spider)使用URL(要爬取页面的网址)构造一个请求(Request)对象,提交给引擎(ENGINE)。如果请求要伪装成浏览器,或者设置代理IP,可以先在爬虫中间件中设置,再发送给引擎。
- 引擎将请求安排给调度器,调度器根据请求的优先级确定执行顺序。
- 引擎从调度器获取即将要执行的请求。
- 引擎通过下载器中间件,将请求发送给下载器下载页面。
- 页面完成下载后,下载器会生成一个响应(Response)对象并将其发送给引擎。下载后的数据会保存于响应对象中。
- 引擎接收来自下载器的响应对象后,通过爬虫中间件,将其发送给爬虫(Spider)进行处理。
- 爬虫将抽取到的一条数据实体(Item)和新的请求(如下一页的链接)发送给引擎。
- 引擎将从爬虫获取到的Item发送给项目管道(ITEM PIPELINES),项目管道实现数据持久化等功能。同时将新的请求发送给调度器,再从第 2 步开始重复执行,直到调度器中没有更多的请求,引擎关闭该网站。
2.3 安装Scrapy
win+R,cmd,这样将安装在C盘。
>pip install scrapy
3. 开始
3.1 创建项目
首先,创建一个myScrapy的文件夹,用于存放创建的项目。由于我的Scrapy框架安装在C盘,所以文件夹和项目也放在了C盘。如果对于Scrapy的相关命令不太清楚,可以敲scrapy这个命令,会有如下图的显示。
这里是对起点中文网的数据进行爬取,所以命名为qidian_hot。
3.2 打开项目
我这里用PyCharm打开myScrapy文件夹,目录结构如下:
我们需要将页面爬取所设计的文件放在spiders目录下,如:qidian_hot.py。
3.3 分析页面
这里对起点中文网小说热销榜的页面的HTML进行分析,设计代码对自己所需要的数据进行抽取。
3.4 代码如下
qidian_hot.py
# -*- coding: utf-8 -*-
from scrapy import Request
from scrapy.spiders import Spider
from qidian_hot.items import QidianHotItem
from scrapy.loader import ItemLoader
class HotSalesSpider(Spider):
name = "hot"#爬虫名称
#start_urls = ["https://www.qidian.com/rank/hotsales?style=1&page=1"]
qidian_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362"}
current_page = 1
# 如何避免爬虫被网站识别出来导致被禁呢?
# 可以重写(override)start_requests()方法,手动生成一个功能更强大的Request对象。
# 因为伪装浏览器、自动登录等功能都是在Request对象中设置的。
def start_requests(self):
url = "https://www.qidian.com/rank/hotsales?style=1&page=1"
yield Request(url, headers=self.qidian_headers, callback=self.hot_parse)
# 引擎是怎么知道要将下载好的页面发送给parse()方法而不是其他方法?能否自定义这个方法?
# 引擎之所以能自动定位,是因为在Request对象中,指定了解析数据的回调函数,而默认情况下,Request指定的解析函数就是parse()方法。
def hot_parse(self,response):#数据解析
#使用xpath定位
list_selector = response.xpath("//div[@class='book-mid-info']")
for one_selector in list_selector:
# #生成ItemLoader的实例
# novel = ItemLoader(item=QidianHotItem(),selector=one_selector)
# novel.add_xpath("name","h4/a/text()")
# novel.add_xpath("author", "p[1]/a[1]/text()")
# novel.add_xpath("type", "p[1]/a[2]/text()")
# novel.add_xpath("form", "p[1]/span/text()")
#
# yield novel.load_item()
#获取小说信息
name = one_selector.xpath("h4/a/text()").extract()[0]
#获取作者
author = one_selector.xpath("p[1]/a[1]/text()").extract()[0]
#获取类型
type = one_selector.xpath("p[1]/a[2]/text()").extract()[0]
#获取形式
form = one_selector.xpath("p[1]/span/text()").extract()[0]
item = QidianHotItem()
item["name"] = name
item["author"] = author
item["type"] = type
item["form"] = form
yield item
#获取下一页URL,并生成一个Request请求
self.current_page += 1
if self.current_page <= 25:
next_url = "https://www.qidian.com/rank/hotsales?style=1&page=%d" % self.current_page
yield Request(next_url, callback=self.hot_parse)
# #定义字典
# hot_dict={
# "name":name,
# "author":author,
# "type":type,
# "form":form
# }
# yield hot_dict
# 如果不使用XPath而使用CSS定位,需要将Request对象中的callback设置为self.css_parse,就可将该函数指定为解析数据的回调函数。
# 建议使用功能更强大的XPath,然后语法更简单的CSS作为XPath的辅助。
def css_parse(self,response):#数据解析
#使用css定位
list_selector = response.css("[class='book-mid-info']")
for one_selector in list_selector:
#获取小说信息
name = one_selector.css("h4>a::text").extract()[0]
#获取作者
author = one_selector.css(".author a::text").extract()[0]
#获取类型
type = one_selector.css(".author a::text").extract()[0]
#获取形式
form = one_selector.css(".author span::text").extract()[0]
#定义字典
hot_dict={
"name":name,
"author":author,
"type":type,
"form":form
}
yield hot_dict
items.py
# -*- coding: utf-8 -*-
import scrapy
class QidianHotItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
name = scrapy.Field()
author = scrapy.Field()
type = scrapy.Field()
form = scrapy.Field()
pass
pipelines.py
# -*- coding: utf-8 -*-
from scrapy.exceptions import DropItem
class QidianHotPipeline(object):
def __init__(self):
self.author_set = set()
def process_item(self, item, spider):
if item["name"] in self.author_set:
raise DropItem("查找到重复姓名的项目:%s"%item)
return item
3.5 运行项目
进入myScrapy文件夹下的qian_hot项目文件夹下,在上方的路径处输入cmd进入命令模式,输入命令scrapy crawl hot -o hot.csv,是将运行的结果保存在hot.csv中。注意.csv文件的编码格式要与项目中的编码一致,可以在settings.py中进行查看和配置。
3.6 运行结果
这里只是显示出运行的结果,数据将会hot.csv文件中持久化。