Python 新手入门不少时候都会写个爬虫练手,本教程使用 Scrapy 框架,帮你简单快速实现爬虫,并将数据保存至数据库。在机器学习中数据挖掘也是十分重要的,个人数据科学老师曾经说过,好算法不如好数据。mysql
Scrapy ,Python 开发的一个快速、高层次的屏幕抓取和 web 抓取框架,用于抓取 web 站点并从页面中提取结构化的数据。文件结构清晰,即便是小白也可以快速上手,总之很是好用😂。git
XPath ,它是一种用来查找 XML 文档中节点位置的语言。 XPath 基于 XML 的树状结构,有不一样类型的节点,包括元素节点,属性节点和文本节点,提供在数据结构树中找寻节点的能力。github
MySQL 是一种关系数据库管理系统,它的优点:它是免费的。做者是下载了 MAMP for Mac ,内嵌MySQL
和Apache
。web
首先经过 Scrapy 爬取到网页后, 经过 XPath 来定位指定元素,获取到你想要的数据,获得数据以后能够将数据存入数据库( MySQL )。简单了解以后就能够开始编写你的爬虫。算法
*重要:下载并查看 Demo ,结合本文能够快速实现一个基本爬虫✌️。sql
安装 Scrapy (系统默认安装了 Python)
:数据库
$ pip install Scrapy
复制代码
在当前目录新建工程json
$ scrapy startproject yourproject
复制代码
新建工程文件结构以下:浏览器
yourproject/
----|scrapy.cfg # 部署配置文件
|yourproject/ # 工程目录
|----__init__.py
|----items.py # 项目数据文件
|----pipelines.py # 项目管道文件
|----settings.py # 项目设置文件
|----spiders/ # 咱们的爬虫 目录
|----__init__.py # 爬虫主要代码在这里
复制代码
简单的爬虫主要使用了spiders
、items
、pipelines
这三个文件:bash
先看看咱们要爬取的网站,这个是 Scrapy 官方 Demo 爬取数据用的网站,咱们先用这个来练手。
分析网页的信息咱们能够看到网页主体是一个列表,列表每一行都包含可一句引用、做者名字、标签等信息。做者名右边点击(about)能够看到做者的详细信息,包括介绍、出生年月日、地点等等。根据上面的数据,咱们能够先建立以下数据模型:
items.py
import scrapy
# quote 咱们要爬取的主体
class QuoteItem(scrapy.Item):
text = scrapy.Field()
tags = scrapy.Field()
author = scrapy.Field()
next_page = scrapy.Field()
pass
# quote 的做者信息 对应 QuoteItem.author
class AuthorItem(scrapy.Item):
name = scrapy.Field()
birthday = scrapy.Field()
address = scrapy.Field()
description = scrapy.Field()
pass
复制代码
全部的模型必须继承scrapy.Item
,完成这一步咱们就能够开始写爬虫的逻辑了。
# 完整的 QuoteItem 数据结构示例
{
text,
tags,
author:{
name,
birthday,
address,
description
}
}
复制代码
既然是爬虫,天然须要去爬取网页,爬虫部分的几个要点:
scrapy.Spider
。name
,启动爬虫时要用。start_requests()
,做为爬虫的起点。parse()
中解析。spiders/init.py
import scrapy
from ScrapySample.items import QuoteItem
from ScrapySample.items import AuthorItem
复制代码
name
->爬虫名字,allowed_domains
->爬取网页的白名单。class QuotesSpider(scrapy.Spider):
name = "quotes"
allowed_domains = ["quotes.toscrape.com"]
复制代码
在start_requests()
中记录你要爬取的网址。
能够只放入一个网址,而后让爬虫本身爬取起始网址中下一页的连接。也能够在这里把全部须要爬的网址直接放入,好比说page
通常是从1开始,而且有序的,写一个for
循环能够直接输入全部页面的网址。
本文使用的是让爬虫本身去爬取下一页网址的方式,因此只写入了一个起始网址。
def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
复制代码
以下代码,爬取网页成功以后,咱们要分析网页结构,找到咱们须要的数据。
咱们先来看XPath语法,//div[@class="col-md-8"]/div[@class="quote"
:这是表示查找 class 为"col-md-8"
的 div 节点下的一个子节点,而且子节点是一个 class 为"quote"
div 节点。若是在当前页面找到了这样一个节点,则返回节点信息,若是没有找到则返回None
。
def parse(self, response):
# 经过查看器,找到列表所在的节点
courses = response.xpath('//div[@class="col-md-8"]/div[@class="quote"]')
for course in courses:
# 将数据模型实例化 并从节点中找到数据填入咱们的数据模型
item = QuoteItem()
# 轮询 course 节点下全部 class 为 "text" 的 span 节点,获取全部匹配到的节点的 text() ,因为获取到的是列表,咱们默认取第一个。
item['text'] = course.xpath('.//span[@class="text"]/text()').extract_first()
item['author'] = course.xpath('.//small[@class="author"]/text()').extract_first()
item['tags'] = course.xpath('.//div[@class="tags"]/a/text()').extract()
# 请求做者详细信息
author_url = course.xpath('.//a/@href').extract_first()
# 若是做者介绍的连接不为空 则去请求做者的详细信息
if author_url != '':
request = scrapy.Request(url='http://quotes.toscrape.com'+author_url, dont_filter=True, callback=self.authorParse)
# 将咱们已经获取到的 QuoteItem 传入该请求的回调函数 authorParse(),在该函数内继续处理做者相关数据。
request.meta['item'] = item
yield request
# 继续爬向下一页 该函数具体实现下面会分析
next_page_request = self.requestNextPage(response)
yield next_page_request
复制代码
这段注释不是很详细,若是看不懂可能须要补一下相关知识。
爬取做者详细信息
成功获取做者详细信息 AuthorItem 后而且赋值给 QuoteItem 的属性 author
,这样一个完整的引述信息 QuoteItem 就组装完成了。
def authorParse(self, response):
# 先获取从 parse() 传递过来的 QuoteItem
item = response.meta['item']
# 经过查看器,找到做者详细信息所在节点
sources = response.xpath('//div[@class="author-details"]')
# 实例化一个做者信息的数据模型
author_item = AuthorItem()
# 往做者信息模型填入数据
for source in sources:
author_item['name'] = source.xpath('.//h3[@class="author-title"]/text()').extract_first()
author_item['birthday'] = source.xpath('.//span[@class="author-born-date"]/text()').extract_first()
author_item['address'] = source.xpath('.//span[@class="author-born-location"]/text()').extract_first()
author_item['description'] = source.xpath('.//div[@class="author-description"]/text()').extract_first()
# 最后将做者信息 author_item 填入 QuoteItem
item['author'] = author_item
# 保存组装好的完整数据模型
yield item
复制代码
爬虫本身找到出路(下一页网页连接)
经过查看器咱们能够找到下一页
按钮元素,找到该节点并提取连接,爬虫即奔向下一个菜园。
def requestNextPage(self, response):
next_page = response.xpath('.//li[@class="next"]/a/@href').extract_first()
# 判断下一个是按钮元素的连接是否存在
if next_page is not None:
if next_page != '':
return scrapy.Request(url='http://quotes.toscrape.com/'+next_page, callback=self.parse)
return None
复制代码
爬虫的主要逻辑到这里就结束了,咱们能够看到,一小段代码就能够实现一个简单的爬虫。通常主流网页都针对防爬虫作了一些处理,实操过程当中也许并不会这么顺利,咱们可能须要模仿浏览器的User-Agent,或者作访问延时防止请求过于频繁等等处理。
pipelines是 Scrapy 用来后续处理的管道,能够同时存在多个,而且能够自定义顺序执行,一般用来作数据处理和数据保存。咱们须要在settings.py
文件中设置须要须要执行的管道和执行顺序。
# 在 settings.py 加入下面的代码
ITEM_PIPELINES = {
'ScrapySample.pipelines.ScrapySamplePipeline': 300,
}
复制代码
在这里我只使用了一个管道ScrapySamplePipeline
,用来将数据保存到数据库当中,后面的数字300
是表示该管道的优先级,数字越小优先级越高。
因为咱们要保存数据到数据库,因此咱们须要先在本地搭建起数据库服务,我这里用的是MySQL
,若是没有搭建的小伙伴能够下个 MAMP 免费版本,安装好傻瓜式操做一键启动Apache
、MySQL
服务。固然,数据库和表仍是要本身建的。
# 在 pipelines.py 中加入数据库配置信息
config = {
'host': '127.0.0.1',
'port': 8081,
'user': 'root',
'password': 'root',
'db': 'xietao',
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor,
}
复制代码
咱们能够在__init__()
函数里作一些初始化工做,好比说链接数据库。
而后process_item()
函数是管道处理事件的函数,咱们要在这里将数据保存入数据库,我在这个函数里写了一些插入数据库操做。
close_spider()
函数是爬虫结束工做时候调用,咱们能够在这里关闭数据库。
class ScrapySamplePipeline(object):
def __init__(self):
# 链接数据库
self.db = sql.connect(**config)
self.cursor = self.db.cursor()
def process_item(self, item, spider):
# 先保存做者信息
sql = 'INSERT INTO author (name, birthday, address, detail) VALUES (%s, %s, %s, %s)'
self.cursor.execute(sql, (item['author']['name'], item['author']['birthday'], item['author']['address'], item['author']['description']))
# 获取做者id
author_id = self.cursor.lastrowid
# 保存引述信息
sql = 'INSERT INTO spider (text, tags, author) VALUES (%s, %s, %s)'
self.cursor.execute(sql, (item['text'], ','.join(item['tags']), author_id))
self.db.commit()
# 即将结束爬虫
def close_spider(self, spider):
self.db.close()
self.cursor.close()
print('close db')
复制代码
若是不须要保存数据库或者对数据处理的话,pipelines
这部分是能够忽略的。这个时候在命令行切换到工程目录下,输入开始执行爬虫命令:
$ scrapy crawl quotes
复制代码
部分不保存到数据库的小伙伴可使用下方命令,将爬取的数据以 Json 格式导出到该工程目录下。
$ scrapy crawl quotes -o quotes.json
复制代码
最后贴上数据库数据成功录入的截图。
这是做者最开始学习 Python 的时候写的,有一些不尽人意的地方后面会再调整,写下本文用意是巩固知识或是用于之后回顾,同时但愿对一样刚开始学习 Python 的读者有所帮助。
最后再次贴上Demo ️。