看到蜘蛛,你可能会想起恶心的真蜘蛛,像这样的,够吓人吧,世界上十种最毒蜘蛛,他算上其中之一。
php
你错了,只是你影像中的可恶的蜘蛛,你万万没想到,蜘蛛还蛮可爱的,像这样的,卡姿兰大眼睛,舍不得狠狠的按在地上摩擦摩擦java
哦,等等,忽然脑子灵光一散,蜘蛛侠,这但是荡气回肠啊,想当年蜘蛛侠还没称为蜘蛛侠的时候,就是被蜘蛛咬了,才称为蜘蛛侠的
python
哦,好像扯远了,仍是回到主题吧,今天的主题是 scrapy 里面的蜘蛛(spider)是指,网络爬虫mysql
今天咱们经过一个完整的例子,爬取虎嗅网新闻列表,我进来网址,看看
linux
https://www.huxiu.com/redis
感受我发现了什么样的宝藏同样,好像能够学习里面的文章写做技巧什么?sql
建立工程数据库
scrapy startproject coolscrapy
这一条命令下去,你不得顺利服从?咱们先来看看目录分布
json
coolscrapy/
scrapy.cfg # 部署配置文件
coolscrapy/ # Python模块,你全部的代码都放这里面
__init__.py
items.py # Item定义文件
pipelines.py # pipelines定义文件
settings.py # 配置文件
spiders/ # 全部爬虫spider都放这个文件夹下面
__init__.py
...
定义咱们本身的 Items
网络
由于咱们须要爬取虎嗅网的新闻列表的《标题》《简述》《连接》《发布时间》,因此咱们须要定义一个 spider.Items 类,来抓取
import scrapy
# 传入 scrapy.Item 说明是继承自 scrapy.Item 基类
class HuXiuItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
link = scrapy.Field()
desc = scrapy.Field()
posttime = scrapy.Field()
或许你会以为定义这个东西,有点麻烦,没有必要,可是你有没有仔细发现,这个不就像 java 里面的基类,定义着各类属性,可能对应了 model 层的数据字段,其实我也不太懂 java,只是公司用的是 java 后台,因此稍微涉略了一下
接下来就是咱们的蜘蛛了
这些蜘蛛,其实就是一些爬取工具,可是抽象到代码层面其实就是一个一个的方法,更加抽象的说法就是一个一个的类(class),Scrapy 使用他们来自 domain(其实就是咱们所说的 url 地址) 爬取信息,在蜘蛛类中定义一个初始化 url,以及跟踪连接,如何解析页面信息
定义一个Spider,只需继承scrapy.Spider
类并定于一些属性:
name: Spider名称,必须是惟一的
start_urls: 初始化下载连接URL
parse(): 用来解析下载后的Response对象,该对象也是这个方法的惟一参数。它负责解析返回页面数据并提取出相应的Item(返回Item对象),还有其余合法的连接URL(返回Request对象)
咱们在coolscrapy/spiders文件夹下面新建huxiu_spider.py
,内容以下
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
Topic: sample
Desc :
"""
from coolscrapy.items import HuXiuItem
import scrapy
class HuXiuSpider(scrapy.Spider):
name = 'huxiu'
allowed_domains = ['huxiu.com']
start_urls = [
'http://www/huxiu.com/index.php'
]
def parse(self, response):
for sel in response.xpath('//div[@class="mod-info-flow"]/div/div[@class="mob-ctt"]'):
item = HuXiuItem()
item['title'] = sel.xpath('h3/a/text()')[0].extract()
item['link'] = sel.xpath('h3/a/@href')[0].extract()
url = response.urljoin(item['link'])
item['desc'] = sel.xpath(
'div[@class="mob-sub"]/text()')[0].extract()
print(item['title'], item['link'], item['desc'])
运行爬虫
难哦你投佛,老天爷保佑个人爬虫安然无事,不出bug,好紧张啊
在根目录执行下面的命令,其中huxiu是你定义的spider名字
scrapy crawl huxiu
老天爷不包邮啊,仍是报错了,居然这样咱们就来解决bug喽
目前暂且留着这个 bug,咱们先来熟悉一下流程吧,后期再改吧
处理连接
若是想继续跟踪每一个新闻连接进去,看看它的详细内容的话,那么能够在parse()方法中返回一个Request对象, 而后注册一个回调函数来解析新闻详情
from coolscrapy.items import HuXiuItem
import scrapy
class HuxiuSpider(scrapy.Spider):
name = "huxiu"
allowed_domains = ["huxiu.com"]
start_urls = [
"http://www.huxiu.com/index.php"
]
def parse(self, response):
for sel in response.xpath('//div[@class="mod-info-flow"]/div/div[@class="mob-ctt"]'):
item = HuXiuItem()
item['title'] = sel.xpath('h3/a/text()')[0].extract()
item['link'] = sel.xpath('h3/a/@href')[0].extract()
url = response.urljoin(item['link'])
item['desc'] = sel.xpath('div[@class="mob-sub"]/text()')[0].extract()
# print(item['title'],item['link'],item['desc'])
yield scrapy.Request(url, callback=self.parse_article)
def parse_article(self, response):
detail = response.xpath('//div[@class="article-wrap"]')
item = HuXiuItem()
item['title'] = detail.xpath('h1/text()')[0].extract()
item['link'] = response.url
item['posttime'] = detail.xpath(
'div[@class="article-author"]/span[@class="article-time"]/text()')[0].extract()
print(item['title'],item['link'],item['posttime'])
yield item
如今parse只提取感兴趣的连接,而后将连接内容解析交给另外的方法去处理了。你能够基于这个构建更加复杂的爬虫程序了
导出数据
最简单的保存抓取数据的方式是使用json格式的文件保存在本地,像下面这样运行:
scrapy crawl huxiu -o items.json
在演示的小系统里面这种方式足够了。不过若是你要构建复杂的爬虫系统, 最好本身编写Item Pipeline
保存数据到数据库
上面咱们介绍了能够将抓取的Item导出为json格式的文件,不过最多见的作法仍是编写Pipeline将其存储到数据库中。咱们在coolscrapy/pipelines.py
定义
# -*- coding: utf-8 -*-
import datetime
import redis
import json
import logging
from contextlib import contextmanager
from scrapy import signals
from scrapy.exporters import JsonItemExporter
from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItem
from sqlalchemy.orm import sessionmaker
from coolscrapy.models import News, db_connect, create_news_table, Article
class ArticleDataBasePipeline(object):
"""保存文章到数据库"""
def __init__(self):
engine = db_connect()
create_news_table(engine)
self.Session = sessionmaker(bind=engine)
def open_spider(self, spider):
"""This method is called when the spider is opened."""
pass
def process_item(self, item, spider):
a = Article(url=item["url"],
title=item["title"].encode("utf-8"),
publish_time=item["publish_time"].encode("utf-8"),
body=item["body"].encode("utf-8"),
source_site=item["source_site"].encode("utf-8"))
with session_scope(self.Session) as session:
session.add(a)
def close_spider(self, spider):
pass
上面我使用了python中的SQLAlchemy来保存数据库,这个是一个很是优秀的ORM库, 我写了篇关于它的入门教程,能够参考下。
而后在setting.py
中配置这个Pipeline,还有数据库连接等信息:
ITEM_PIPELINES = {
'coolscrapy.pipelines.ArticleDataBasePipeline': 5,
}
# linux pip install MySQL-python
DATABASE = {'drivername': 'mysql',
'host': '192.168.203.95',
'port': '3306',
'username': 'root',
'password': 'mysql',
'database': 'spider',
'query': {'charset': 'utf8'}
}
再次运行爬虫
明天再解决这个 bug 吧