从零开始学python(十四)百万高性能框架scrapy框架

前言

回顾之前讲述了python语法编程 必修入门基础和网络编程,多线程/多进程/协程等方面的内容,后续讲到了数据库编程篇MySQL,Redis,MongoDB篇,和机器学习,全栈开发,数据分析,爬虫数据采集/自动化和抓包前面没看的也不用往前翻,系列文已经整理好了:

1.跟我一起从零开始学python(一)编程语法必修
2.跟我一起从零开始学python(二)网络编程
3.跟我一起从零开始学python(三)多线程/多进程/协程
4.跟我一起从零开始学python(四)数据库编程:MySQL数据库
5.跟我一起从零开始学python(五)数据库编程:Redis数据库
6.跟我一起从零开始学python(六)数据库编程:MongoDB数据库
7.跟我一起从零开始学python(七)机器学习
8.跟我一起从零开始学python(八)全栈开发
9.跟我一起从零开始学python(九)数据分析
10.跟我一起从零开始学python(十)Hadoop从零开始入门
11.跟我一起从零开始学python(十一)简述spark
12.跟我一起从零开始学python(十二)如何成为一名优秀的爬虫工程师

本系列文根据以下学习路线展开讲述,由于内容较多,:

从零开始学python到高级进阶路线图

框架源码专题

一丶scrapy框架

一丶框架基本使用

Scrapy是一个用于爬取网站数据的Python框架。它提供了一套强大的工具和API,可以简化爬取、处理和存储数据的过程。下面我将详细解释Scrapy框架的基本使用。

1.安装Scrapy:

首先,确保已在Python环境中安装了pip(Python包管理器)。然后,可以使用以下命令在命令行中安装Scrapy:

pip install scrapy

2.创建Scrapy项目:

在命令行中,使用以下命令创建一个新的Scrapy项目:

scrapy startproject project_name

这将在当前目录下创建一个名为project_name的文件夹,其中包含Scrapy项目的基本结构。

3.定义爬虫:

在Scrapy项目中,爬虫是用于定义如何爬取特定网站的类。在项目的spiders目录中,可以创建一个新的Python文件来定义你的爬虫。下面是一个简单的示例:

import scrapy

class MySpider(scrapy.Spider):
    name = 'example'
    start_urls = ['http://www.example.com']

    def parse(self, response):
        # 在这里处理网页响应,提取数据等
        pass

在上面的示例中,我们定义了一个名为MySpider的爬虫,指定了名称为example,并指定了起始URL为http://www.example.com。在parse方法中,你可以处理网页响应,并提取你需要的数据。

4.提取数据:

在parse方法中,可以使用Scrapy提供的选择器来提取网页中的数据。Scrapy支持多种选择器,如XPath和CSS选择器。下面是一个使用XPath提取数据的示例:

def parse(self, response):
    titles = response.xpath('//h1/text()').getall()
    for title in titles:
        yield {
            'title': title
        }

在上面的示例中,我们使用XPath选择器提取网页中所有<h1>标签的文本内容,并将其封装为一个字典。然后使用yield语句将字典作为一个数据项返回。

5.定义数据存储:

Scrapy提供了多种数据存储的方式,如存储为JSON、CSV或数据库。你可以在项目的pipelines.py文件中定义数据存储管道。下面是一个简单的示例:

import json

class JsonWriterPipeline:
    def open_spider(self, spider):
        self.file = open('data.json', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + '\n'
        self.file.write(line)
        return item

在上面的示例中,我们定义了一个将爬取的数据存储为JSON格式的管道。在process_item方法中,我们将数据项转换为JSON格式,并写入文件。你也可以根据需要自定义其他存储管道,如存储到数据库中。

6.运行爬虫:

如何运行爬虫取决于你的需求。在命令行中,可以使用以下命令运行爬虫:

scrapy crawl example

这里的example是爬虫的名称,对应MySpider类的name属性。Scrapy将会开始运行爬虫,并根据设定的规则爬取网页并处理数据。

这些是Scrapy框架的基本使用方法。通过定义爬虫、提取数据和设置数据存储管道,你可以利用Scrapy框架快速、高效地爬取和处理网站数据。你还可以进一步研究Scrapy的高级功能,如设置请求头、处理页面间的链接、使用中间件等。官方文档为进一步学习Scrapy提供了详细的介绍和示例代码:https://docs.scrapy.org/

二丶scrapy功能学习

1.Selector数据处理

在Scrapy框架中,使用Selector类对网页进行数据提取和处理是常见的操作之一。Selector提供了强大的API,支持使用XPath选择器或CSS选择器来定位和提取网页中的数据。下面我将详细解释Selector的使用方法。

首先,你需要导入Selector类:

from scrapy import Selector

然后,你可以使用Selector类来创建一个选择器对象,并将网页的内容作为参数传入:

# 以网页内容创建Selector对象
selector = Selector(text=html_content)

这里的html_content是网页的内容,可以是字符串形式的HTML代码或网页响应的文本。

接下来,可以使用选择器对象来提取和处理数据。

  • 使用XPath选择器提取数据
# 使用XPath选择器提取
data = selector.xpath('//h1/text()').get()
  • 使用CSS选择器提取数据
# 使用CSS选择器提取
data = selector.css('h1::text').get()
  • 提取多个数据
# 提取多个数据
data_list = selector.xpath('//div[@class="item"]/text()').getall()
  • 嵌套选择器
# 嵌套选择器
parent_element = selector.xpath('//div[@class="parent"]')
data = parent_element.xpath('./span/text()').get()

2.xpath选择器

在Scrapy框架源码中,XPath选择器被广泛用于网页数据的提取和处理。XPath是一种用于在HTML/XML文档中定位元素的查询语言,通过使用XPath选择器,可以方便地定位和提取网页中的数据。下面我将详细解释XPath选择器的用法和功能。

1.XPath基本语法:

XPath使用路径表达式来描述元素的位置,路径表达式由一系列的节点选择器和轴运算符组成。以下是XPath的一些基本语法规则:

  • /: 表示从根节点开始的绝对路径,例如:/html/body/div.
  • //: 表示在整个文档中搜索符合条件的元素,例如://div.
  • .: 表示当前节点,例如:./span.
  • ..: 表示当前节点的父节点,例如:../div.
  • @: 表示获取元素的属性值,例如:@href.

2.XPath节点选择器:

XPath提供了多种节点选择器,用于选择和匹配不同类型的元素。以下是一些常用的节点选择器:

  • nodename: 选择所有指定节点名称的元素,例如:div.
  • : 选择所有子元素,例如:.
  • @attribute: 选择指定属性的元素,例如:@href.
  • [@attribute='value']: 根据属性值选择元素,例如:- [@class='container'].

3.XPath轴运算符:

轴运算符用于根据元素的相对位置选择元素。以下是一些常用的轴运算符:

  • ancestor::: 选择所有祖先节点,例如:ancestor::div.
  • parent::: 选择当前节点的父节点,例如:parent::div.
  • preceding-sibling::: 选择当前节点之前的所有同级节点,例如:preceding-sibling::div.

4.使用XPath选择器提取数据:

在Scrapy中,可以使用Selector类的xpath()方法来执行XPath选择器。下面是一些示例:

from scrapy.selector import Selector

# 创建Selector对象
selector = Selector(text=html_content)

# 提取文本内容
data = selector.xpath('//h1/text()').get()

# 提取属性值
href = selector.xpath('//a/@href').get()

# 提取多个数据
data_list = selector.xpath('//div[@class="item"]/text()').getall()

在上面的示例中,我们首先创建了一个Selector对象,其中html_content是网页的内容。然后使用xpath()方法并传入XPath表达式来选择和提取数据。get()方法用于获取第一个匹配项,而getall()方法用于获取所有匹配项的列表。

XPath选择器的功能非常强大,你可以根据具体的网页结构和需求编写自己的选择器表达式来提取和处理网页中的数据。同时,XPath还支持诸如谓语(Predicates)、逻辑运算符(and、or、not)、函数(contains、starts-with、normalize-space)等高级功能,可以进一步扩展和定制你的选择器。

3.CSS选择器

在Scrapy框架源码中,CSS选择器也是一种常用的方法来提取和处理网页数据。与XPath选择器相比,CSS选择器使用起来更简洁直观。下面我将详细讲解CSS选择器的用法和功能。

1.基本语法:

CSS选择器使用简洁的语法来选择元素。以下是一些基本的CSS选择器语法:

  • tagname: 选择指定标签名的元素,例如:div.
  • .#id: 选择具有指定id的元素,例如:#container.
  • .class: 选择具有指定class的元素,例如:.item.
  • *: 选择所有元素.
  • element1, element2: 同时选择多个元素,例如:div, span.

2.层级关系和子元素选择:

CSS选择器支持选择元素的子元素和后代元素。以下是一些示例:

  • parent > child: 选择父元素下的直接子元素,例如:div > span.
  • ancestor descendant: 选择祖先元素下的后代元素,例如:body span.

3.属性选择器:

CSS选择器还支持根据元素的属性进行选择。以下是一些常见的属性选择器:


4.伪类选择器:

伪类选择器用于选择具有特殊状态或特定位置的元素。以下是一些常见的伪类选择器:

  • :first-child: 选择父元素的第一个子元素.
  • :last-child: 选择父元素的最后一个子元素.
  • :nth-child(n): 选择父元素的第n个子元素.
  • :not(selector): 选择不匹配给定选择器的元素.

5.使用CSS选择器提取数据:

在Scrapy中,可以使用Selector类的css()方法来执行CSS选择器。下面是一些示例:

from scrapy.selector import Selector

# 创建Selector对象
selector = Selector(text=html_content)

# 提取文本内容
data = selector.css('h1::text').get()

# 提取属性值
href = selector.css('a::attr(href)').get()

# 提取多个数据
data_list = selector.css('div.item::text').getall()

在上面的示例中,我们首先创建了一个Selector对象,其中html_content是网页的内容。然后使用css()方法并传入CSS选择器表达式来选择和提取数据。get()方法用于获取第一个匹配项,而getall()方法用于获取所有匹配项的列表。

CSS选择器的语法简洁明了,易于理解和使用。通过灵活运用CSS选择器,你可以在Scrapy框架中方便地提取和处理网页数据。

4.scrapy对接MySQL

在Scrapy框架中,将数据存储到MySQL数据库是一种常见的需求。Scrapy提供了一个方便的方式来实现与MySQL数据库的对接。下面我将详细说明如何在Scrapy框架中对接MySQL数据库。

1.安装MySQL驱动:

首先,确保已经安装了Python的MySQL驱动程序。在Scrapy中,常用的MySQL驱动包括mysql-connector-pythonpymysql。你可以使用以下命令来安装其中一个驱动程序:

pip install mysql-connector-python

pip install pymysql

2.配置数据库连接:

在Scrapy项目的settings.py文件中,可以配置MySQL数据库连接信息。例如,你需要指定数据库主机、数据库名称、用户名和密码等。以下是一个示例的配置:

# MySQL数据库连接信息
MYSQL_HOST = 'localhost'
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydatabase'
MYSQL_USER = 'myuser'
MYSQL_PASSWORD = 'mypassword'

3.创建数据库连接:

在Scrapy的爬虫代码中,你可以使用以上配置信息来创建与MySQL数据库的连接。在Spider类的__init__方法中,可以使用MySQL驱动来建立数据库连接。以下是一个示例代码:

import mysql.connector

class MySpider(scrapy.Spider):

    def __init__(self, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.conn = mysql.connector.connect(
            host=settings.MYSQL_HOST,
            port=settings.MYSQL_PORT,
            database=settings.MYSQL_DATABASE,
            user=settings.MYSQL_USER,
            password=settings.MYSQL_PASSWORD
        )
        self.cursor = self.conn.cursor()

4.存储数据到数据库:

在Scrapy的爬虫代码中,当你需要将数据存储到MySQL数据库时,可以通过执行SQL语句来实现。以下是一个示例代码:

class MySpider(scrapy.Spider):

    # ...

    def parse(self, response):
        # 解析响应数据
        data = {
            'title': response.xpath('//title/text()').get(),
            'content': response.xpath('//div[@class="content"]/text()').get()
        }

        # 执行插入数据的SQL语句
        sql = "INSERT INTO mytable (title, content) VALUES (%s, %s)"
        values = (data['title'], data['content'])
        self.cursor.execute(sql, values)
        self.conn.commit()

在上面的示例中,我们定义了一个parse方法,从响应中提取数据,并将其存储到MySQL数据库中。我们执行了一个插入数据的SQL语句,并使用execute()方法执行该语句,然后使用commit()方法提交事务。

需要注意的是,当爬虫关闭时,你应该在爬虫的closed方法中关闭数据库连接,以释放资源。以下是一个示例代码:

class MySpider(scrapy.Spider):

    # ...

    def closed(self, reason):
        self.cursor.close()
        self.conn.close()

以上就是在Scrapy框架中对接MySQL数据库的详细步骤。通过配置数据库连接信息,创建数据库连接,然后执行SQL语句来存储数据,你可以方便地将爬取到的数据保存到MySQL数据库中。

5.Scrapy对接MongoDB

在Scrapy框架中,对接MongoDB数据库是一种常见的需求。Scrapy提供了一个方便的方式来实现与MongoDB的对接。下面我将详细说明如何在Scrapy框架中对接MongoDB数据库。

1.安装MongoDB驱动:
首先,确保已经安装了Python的MongoDB驱动程序。在Scrapy中,常用的MongoDB驱动包括pymongo和mongoengine。你可以使用以下命令来安装其中一个驱动程序:

pip install pymongo

pip install mongoengine

2.配置数据库连接:

在Scrapy项目的settings.py文件中,可以配置MongoDB数据库连接信息。例如,你需要指定数据库主机、数据库名称等。以下是一个示例的配置:

# MongoDB数据库连接信息
MONGO_URI = 'mongodb://localhost:27017/'
MONGO_DATABASE = 'mydatabase'

3.创建数据库连接:

在Scrapy的爬虫代码中,你可以使用以上配置信息来创建与MongoDB数据库的连接。在Spider类的init方法中,可以使用MongoDB驱动来建立数据库连接。以下是一个示例代码:

from pymongo import MongoClient

class MySpider(scrapy.Spider):

    def __init__(self, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.client = MongoClient(settings.MONGO_URI)
        self.db = self.client[settings.MONGO_DATABASE]

4.存储数据到数据库:

在Scrapy的爬虫代码中,当你需要将数据存储到MongoDB数据库时,可以使用相应的MongoDB驱动提供的方法来实现。以下是一个示例代码:

class MySpider(scrapy.Spider):

    # ...

    def parse(self, response):
        # 解析响应数据
        data = {
            'title': response.xpath('//title/text()').get(),
            'content': response.xpath('//div[@class="content"]/text()').get()
        }

        # 存储数据到MongoDB集合
        collection = self.db['mycollection']
        collection.insert_one(data)

在上面的示例中,我们定义了一个parse方法,从响应中提取数据,并将其存储到MongoDB数据库中。我们通过insert_one()方法将数据插入到指定的集合中。

需要注意的是,当爬虫关闭时,你应该在爬虫的closed方法中关闭数据库连接,以释放资源。以下是一个示例代码:

class MySpider(scrapy.Spider):

    # ...

    def closed(self, reason):
        self.client.close()

以上就是在Scrapy框架中对接MongoDB数据库的详细步骤。通过配置数据库连接信息,创建数据库连接,然后使用相应的驱动方法存储数据,你可以方便地将爬取到的数据保存到MongoDB数据库中。

6.Scrapy文件存储

在Scrapy框架中,文件存储是一个常见的需求,特别是在网络爬虫中,我们经常需要将爬取到的数据以文件的形式保存下来。Scrapy提供了多种方式来实现文件存储,包括保存为本地文件、存储到云存储服务(如Amazon S3)、存储到FTP服务器等。下面我将详细介绍Scrapy框架中文件存储的几种方式。

1.保存为本地文件:

最简单的文件存储方式是将数据保存为本地文件。在Scrapy的爬虫代码中,你可以通过在settings.py文件中配置FEED_URI和FEED_FORMAT来实现。以下是一个示例配置:

# 保存为本地文件
FEED_URI = 'result.json'
FEED_FORMAT = 'json'

在以上配置中,FEED_URI指定了保存的文件路径和文件名,FEED_FORMAT指定了保存的文件格式。你可以将格式设为json、csv、xml等等。

2.存储到云存储服务(如Amazon S3):

如果你希望将文件存储到云存储服务,如Amazon S3,Scrapy也提供了相应的方式来实现。首先,你需要安装scrapy-extensions扩展包,可以通过以下命令进行安装:

pip install scrapy-extensions

然后,在settings.py文件中配置相应的信息。以下是一个示例配置:

# 存储到Amazon S3
FEED_URI = 's3://mybucket/result.json'
FEED_FORMAT = 'json'
AWS_ACCESS_KEY_ID = 'your_access_key_id'
AWS_SECRET_ACCESS_KEY = 'your_secret_access_key'

在以上配置中,FEED_URI指定了存储的目标位置,这里是Amazon S3的桶和文件名,FEED_FORMAT指定了保存的文件格式。同时,你需要提供有效的Amazon S3访问凭证,即AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY。

3.存储到FTP服务器:

如果你希望将文件存储到FTP服务器,Scrapy同样提供了支持。在settings.py文件中,你可以配置FTP服务器的连接信息。以下是一个示例配置:

# 存储到FTP服务器
FEED_URI = 'ftp://username:password@ftp.example.com/result.json'
FEED_FORMAT = 'json'

在以上配置中,FEED_URI指定了FTP服务器的连接信息,包括用户名、密码、服务器地址和保存的文件名,FEED_FORMAT指定了保存的文件格式。

需要注意的是,以上配置项是在settings.py文件中进行配置的,具体的文件存储方式取决于你的需求。你可以根据自己的实际情况选择适合的文件存储方式。在爬虫代码中,当爬取到数据后,Scrapy会自动将数据保存到指定的文件位置。

三丶scrapy中间件

Scrapy框架中的中间件(Middleware)是其强大灵活的机制之一,它允许开发者在请求(Request)和响应(Response)的处理过程中进行拦截、修改或扩展。中间件可以用于实现各种功能,如请求和响应的处理、User-Agent的随机切换、代理设置、错误处理等。在本文中,我将为你详细解释Scrapy中间件的原理和使用方法。

1、什么是中间件?

在Scrapy中,中间件是一系列组件,可以对每个请求和响应进行处理。Scrapy的请求和响应经过一系列中间件的处理,每个中间件可以在请求或响应经过自己时执行预定义的操作,然后继续将请求或响应传递给后续的中间件。中间件以管道(Pipeline)的方式连接在一起,形成一个处理链。Scrapy默认提供了一些中间件,同时也允许开发者定制自己的中间件。

2、Scrapy中的中间件类型

Scrapy中的中间件分为两类:请求中间件(Request Middleware)和响应中间件(Response Middleware)。请求中间件在请求发送之前执行,可以对请求进行修改、拦截或进行预处理。响应中间件在得到响应后执行,可以对响应进行修改、拦截或进行后处理。

3、中间件的执行顺序

Scrapy中的中间件执行顺序可以通过在settings.py文件中的DOWNLOADER_MIDDLEWARES和SPIDER_MIDDLEWARES配置项中设置中间件的顺序来控制。数值越小的中间件会越早执行。这些配置项是一个包含中间件类路径的字典,可以对其中的中间件进行排序和启用/禁用。同时,还可以通过process_request、process_response等方法的priority属性控制中间件方法的执行顺序。

4、中间件的编写

为了编写一个自定义的中间件,你需要创建一个类并实现Scrapy提供的中间件基类的方法。以下是一个简单示例:

class MyMiddleware:
    def process_request(self, request, spider):
        # 处理请求的自定义逻辑
        return None

    def process_response(self, request, response, spider):
        # 处理响应的自定义逻辑
        return response

在上述示例中,MyMiddleware是一个自定义的中间件类。其中,process_request()方法在发起请求前会被调用,可以对请求进行修改或拦截。process_response()方法在收到响应后会被调用,可以对响应进行修改或后处理。注意,需要在方法中返回相应的请求或响应对象,以便中间件链的下一个中间件继续处理。

5、中间件的配置

为了启用和配置自定义的中间件,你需要在settings.py文件中进行相应的配置。以下是一个示例配置:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.MyMiddleware': 543,
    # 其他中间件...
}

在上述示例中,DOWNLOADER_MIDDLEWARES配置项指定了下载器中间件的配置。其中,543是中间件的优先级,数值越小的中间件会越早执行。myproject.middlewares.MyMiddleware是自定义中间件的类路径。

6、常见的中间件应用场景

  • 请求预处理:可以在请求中间件中进行一些通用的预处理操作,如添加通用的请求头信息、设置代理等。
  • User-Agent随机切换:可以在请求中间件中随机选择User-Agent,以避免被大量请求的网站识别为爬虫。
  • 代理设置:可以在请求中间件中设置代理,以实现IP的轮换或匿名性。
  • 防止重复请求:可以在请求中间件中根据一定的规则过滤掉重复的请求。
  • 错误处理:可以在响应中间件中对处理请求时发生的错误进行处理,如超时、连接错误等。

以上是中间件的一些常见应用场景,你可以根据自己的需求开发相应的中间件来实现这些功能。

总结
Scrapy中的中间件是其强大灵活的机制之一,可以通过编写自定义的中间件来实现各种功能。中间件分为请求中间件和响应中间件,可以对每个请求和响应进行拦截、修改或扩展。通过配置中间件的顺序和优先级,可以控制中间件的执行顺序。常见的中间件应用场景包括请求预处理、User-Agent随机切换、代理设置、防止重复请求和错误处理等
程语法-机器学习-全栈开发-数据分析-爬虫-APP逆向等全套项目+文档**

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容