scrapy的快速入门(三)

总结一下之前的spider,总的来说,Spider类就是定义了如何爬取某个(或某些)网站。包括了爬取的动作以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。

对spider来说,爬取的循环类似下文:
1、以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。
spider中初始的request是通过调用 start_requests() 来获取的。 start_requests() 读取 start_urls 中的URL, 并以parse 为回调函数生成 Request
2、在回调函数内分析返回的(网页)内容,返回 Item 对象或者 Request 或者一个包括二者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。
3、回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。
4、最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。

虽然该循环对任何类型的spider都适用,但Scrapy仍然为了不同的需求提供了多种默认spider。下面将简单介绍这些spider。

内置Spider参考手册:
Scrapy提供多种方便的通用spider供您继承使用。 这些spider为一些常用的爬取情况提供方便的特性, 例如根据某些规则跟进某个网站的所有链接、根据 Sitemaps 来进行爬取,或者分析XML/CSV源。
主要包括:scrapy.SpiderCrawlSpiderXMLFeedSpiderCSVFeedSpiderSitemapSpider
下面主要介绍一下scrapy.Spider和CrawlSpider
一、scrapy.Spider
Spider是最简单的spider。每个其他的spider必须继承自该类(包括Scrapy自带的其他spider以及您自己编写的spider)。 Spider并没有提供什么特殊的功能。 其仅仅请求给定的 start_urls/start_requests ,并根据返回的结果(resulting responses)调用spider的 parse 方法。

name:定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。 不过您可以生成多个相同的spider实例(instance),这没有任何限制。 name是spider最重要的属性,而且是必须的。 如果该spider爬取单个网站(single domain),一个常见的做法是以该网站(domain)(加或不加 后缀 )来命名spider。 例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite 。

allowed_domains:可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进。

start_urls:URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。

custom_settings:该属性由初始化类之后由from_crawler()类方法设置,并链接到此蜘蛛实例绑定到的Crawler对象。
Crawlers在项目中封装了大量组件,用于单一访问(例如扩展,中间件,信号管理器等)。请参阅Crawler API了解更多关于它们。

crawler:该属性由初始化类之后由from_crawler()类方法设置,并链接到此蜘蛛实例绑定到的Crawler对象。
Crawlers在项目中封装了大量组件,用于单一访问(例如扩展,中间件,信号管理器等)。请参阅Crawler API了解更多关于它们。

start_requests():该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。 当spider启动爬取并且未制定URL时,该方法被调用。 当指定了URL时,make_requests_from_url() 将被调用来创建Request对象。 该方法仅仅会被Scrapy调用一次,因此您可以将其实现为生成器。 该方法的默认实现是使用 start_urls 的url生成Request。
如果您想要修改最初爬取某个网站的Request对象,您可以重写(override)该方法。 例如,如果您需要在启动时以POST登录某个网站,你可以这么写:

def start_requests(self):
    return [scrapy.FormRequest("http://www.example.com/login",
               formdata={'user': 'john', 'pass': 'secret'},
               callback=self.logged_in)
           ]

def logged_in(self, response):
    # here you would extract links to follow and return Requests for
    # each of them, with another callback
    pass

make_requests_from_url(url):该方法接受一个URL并返回用于爬取的 Request 对象。 该方法在初始化request时被 start_requests() 调用,也被用于转化url为request。 默认未被复写(overridden)的情况下,该方法返回的Request对象中, parse() 作为回调函数,dont_filter参数也被设置为开启。

parse(response):当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法。 parse 负责处理response并返回处理的数据以及(/或)跟进的URL。 Spider 对其他的Request的回调函数也有相同的要求。 该方法及其他的Request回调函数必须返回一个包含 Request 及(或) Item 的可迭代的对象。

log(message[, level, component]):使用 scrapy.log.msg() 方法记录(log)message。 log中自动带上该spider的 name 属性。详情请参见 Logging

closed(reason):当spider关闭时,该函数被调用。 该方法提供了一个替代调用signals.connect()来监听spider_closed 信号的快捷方式。

scrapy.Spider的例子,这里就不详细介绍了,之前的文章都是继承scrapy.Spider完成的;

二、CrawlSpider
爬取一般网站常用的spider。其定义了一些规则(rule)来提供跟进link的方便的机制。 也许该spider并不是完全适合您的特定网站或项目,但其对很多情况都使用。 因此您可以以其为起点,根据需求修改部分方法。当然您也可以实现自己的spider。

除了从Spider继承过来的(您必须提供的)属性外,其提供了一个新的属性:
rules:一个包含一个(或多个) Rule 对象的集合(list)。 每个 Rule 对爬取网站的动作定义了特定表现。 Rule对象在下边会介绍。 如果多个rule匹配了相同的链接,则根据他们在本属性中被定义的顺序,第一个会被使用。

parse_start_url(response):是一个可复写(overrideable)的方法,当start_url的请求返回时,该方法被调用。 该方法分析最初的返回值并必须返回一个 Item 对象或者 一个 Request 对象或者 一个可迭代的包含二者对象。

爬取规则(Crawling rules):

class scrapy.contrib.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)

link_extractor 是一个 Link Extractor 对象。 其定义了如何从爬取到的页面提取链接。
callback 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中每获取到链接时将会调用该函数。该回调函数接受一个response作为其第一个参数, 并返回一个包含 Item 以及(或) Request 对象(或者这两者的子类)的列表(list)。
cb_kwargs 包含传递给回调函数的参数(keyword argument)的字典。
follow 是一个布尔(boolean)值,指定了根据该规则从response提取的链接是否需要跟进。 如果 callback 为None, follow 默认设置为 True ,否则默认为 False 。
process_links 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤。
process_request 是一个callable或string(该spider中同名的函数将会被调用)。 该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。 (用来过滤request)
restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。还有一个类似的restrict_cs
下面总结一下:
1、CrawlSpider的工作原理:
CrawlSpider继承了Spider,所以具有Spider的所有函数。
先由start_requests对start_urls中的每一个url发起请求(make_requests_from_url),这个请求会被parse接收。在Spider里面的parse需要我们定义,但CrawlSpider定义parse去解析响应(self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True));_parse_response根据有无callback,follow和self.follow_links执行不同的操作;其中_requests_to_follow又会获取link_extractor(这个是我们传入的LinkExtractor)解析页面得到的link(link_extractor.extract_links(response)),对url进行加工(process_links,需要自定义),对符合的link发起Request。使用.process_request(需要自定义)处理响应。
下面是对应的源码:

def _parse_response(self, response, callback, cb_kwargs, follow=True):
    ##首先,如果传入了callback,使用这个callback解析页面并获取解析得到的reques或item
        if callback:
            cb_res = callback(response, **cb_kwargs) or ()
            cb_res = self.process_results(response, cb_res)
            for requests_or_item in iterate_spider_output(cb_res):
                yield requests_or_item
    ## 然后,判断有无follow,用_requests_to_follow解析响应是否有符合要求的link。
        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

2、CrawlSpider获取rules的原理:
CrawlSpider类会在init方法中调用_compile_rules方法,然后在其中浅拷贝rules中的各个Rule获取要用于回调(callback),要进行处理的链接(process_links)和要进行的处理请求(process_request)
对应的源码:

def _compile_rules(self):
        def get_method(method):
            if callable(method):
                return method
            elif isinstance(method, six.string_types):
                return getattr(self, method, None)

        self._rules = [copy.copy(r) for r in self.rules]
        for rule in self._rules:
            rule.callback = get_method(rule.callback)
            rule.process_links = get_method(rule.process_links)
            rule.process_request = get_method(rule.process_request)

Rule的源码:

class Rule(object):

        def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
            self.link_extractor = link_extractor
            self.callback = callback
            self.cb_kwargs = cb_kwargs or {}
            self.process_links = process_links
            self.process_request = process_request
            if follow is None:
                self.follow = False if callback else True
            else:
                self.follow = follow

最终结果是:LinkExtractor会传给link_extractor。
3、_parse_response会处理有callback的(响应)response,对于有callback参数Rule是传给指定的函数处理,
没有callback的处理:
cb_res = callback(response, **cb_kwargs) or ()
而_requests_to_follow会将self._response_downloaded传给callback用于对页面中匹配的url发起请求(request)。
r = Request(url=link.url, callback=self._response_downloaded)

这里贴上Scrapy.spiders.CrawlSpider的完整源码:

"""
This modules implements the CrawlSpider which is the recommended spider to use
for scraping typical web sites that requires crawling pages.

See documentation in docs/topics/spiders.rst
"""

import copy
import six

from scrapy.http import Request, HtmlResponse
from scrapy.utils.spider import iterate_spider_output
from scrapy.spiders import Spider


def identity(x):
    return x


class Rule(object):

    def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
        self.link_extractor = link_extractor
        self.callback = callback
        self.cb_kwargs = cb_kwargs or {}
        self.process_links = process_links
        self.process_request = process_request
        if follow is None:
            self.follow = False if callback else True
        else:
            self.follow = follow


class CrawlSpider(Spider):

    rules = ()

    def __init__(self, *a, **kw):
        super(CrawlSpider, self).__init__(*a, **kw)
        self._compile_rules()

    def parse(self, response):
        return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)

    def parse_start_url(self, response):
        return []

    def process_results(self, response, results):
        return results

    def _requests_to_follow(self, response):
        if not isinstance(response, HtmlResponse):
            return
        seen = set()
        for n, rule in enumerate(self._rules):
            links = [lnk for lnk in rule.link_extractor.extract_links(response)
                     if lnk not in seen]
            if links and rule.process_links:
                links = rule.process_links(links)
            for link in links:
                seen.add(link)
                r = Request(url=link.url, callback=self._response_downloaded)
                r.meta.update(rule=n, link_text=link.text)
                yield rule.process_request(r)

    def _response_downloaded(self, response):
        rule = self._rules[response.meta['rule']]
        return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)

    def _parse_response(self, response, callback, cb_kwargs, follow=True):
        if callback:
            cb_res = callback(response, **cb_kwargs) or ()
            cb_res = self.process_results(response, cb_res)
            for requests_or_item in iterate_spider_output(cb_res):
                yield requests_or_item

        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

    def _compile_rules(self):
        def get_method(method):
            if callable(method):
                return method
            elif isinstance(method, six.string_types):
                return getattr(self, method, None)

        self._rules = [copy.copy(r) for r in self.rules]
        for rule in self._rules:
            rule.callback = get_method(rule.callback)
            rule.process_links = get_method(rule.process_links)
            rule.process_request = get_method(rule.process_request)

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(CrawlSpider, cls).from_crawler(crawler, *args, **kwargs)
        spider._follow_links = crawler.settings.getbool(
            'CRAWLSPIDER_FOLLOW_LINKS', True)
        return spider

    def set_crawler(self, crawler):
        super(CrawlSpider, self).set_crawler(crawler)
        self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)

接下来给出配合rule使用CrawlSpider的例子:
爬取豆瓣图书
1、首先确定要爬取的数据;
items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class DoubanbookItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()  # 书名
    images = scrapy.Field()  # 图片
    author = scrapy.Field()  # 作者
    press = scrapy.Field()  # 出版社
    date = scrapy.Field()  # 出版日期
    page = scrapy.Field()  # 页数
    price = scrapy.Field()  # 价格
    ISBN = scrapy.Field()  # ISBN号
    score = scrapy.Field()  # 豆瓣评分
    author_profile = scrapy.Field()  # 作者简介
    content_description = scrapy.Field()  # 内容简介
    link = scrapy.Field()  # 详情页链接

2、最主要的爬虫部分:
doubanbooks.py

# -*- coding: utf-8 -*-
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import DoubanbookItem
import re
import os
import urllib.request
from scrapy.http import HtmlResponse, Request
from scrapy.conf import settings  # 从settings文件中导入Cookie,这里也可以from scrapy.conf import settings.COOKIE
import random
import string


class BookspiderSpider(CrawlSpider):
    name = 'bookSpider'
    allowed_domains = ['book.douban.com']
    cookie = settings['COOKIE']  # 带着Cookie向网页发请求
    #获取随机的cookies
    cookies = "bid=%s" % "".join(random.sample(string.ascii_letters + string.digits, 11))
    start_urls = ['https://book.douban.com/tag/数据分析?start=0&type=T']
    rules = (
        # 列表页url
        Rule(LinkExtractor(allow=(r"tag/数据分析?start=\d+&type=T")),follow = True),
        # 详情页url
        Rule(LinkExtractor(allow=(r"subject/\d+/$")), callback="parse_item",  follow = True)
    )
    #将获取到的cookie传递给每一个url链接的ruquest
    def request_question(self, request):
        return Request(request.url, meta={'cookiejar': 1}, callback=self.parse_item)

    #获取详情页具体的图书信息
    def parse_item(self, response):

        if response.status == 200:
            item = DoubanbookItem()
            # 图书名
            item["name"] = response.xpath("//div[@id='wrapper']/h1/span/text()").extract()[0].strip()
            # 图书的图片
            src = response.xpath("//div[@id='mainpic']/a/img/@src").extract()[0].strip()
            file_name = "%s.jpg" % (item["name"])  # 图书名
            file_path = os.path.join("E:\\spider\\pictures\\douban_book\\book_img", file_name)  # 拼接这个图片的路径
            opener = urllib.request.build_opener()
            opener.addheaders = [('User-Agent',
                                  'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
            urllib.request.install_opener(opener)
            urllib.request.urlretrieve(src, file_path)  # 接收文件路径和需要保存的路径,会自动去文件路径下载并保存到我们指定的本地路径
            item["images"] = file_path
            #作者
            if len(response.xpath("//div[@id='info']/span[1]/a/text()").extract()) > 0:
                authors = response.xpath("//div[@id='info']/span[1]/a/text()").extract()
                item["author"] = ",".join(author.strip() for author in authors).strip()
            else:
                authors = response.xpath("//div[@id='info']/a[1]/text()").extract()
                item["author"] = ",".join(author.strip() for author in authors).strip()
            #出版社
            try:
                item["press"] = response.xpath("//div[@id='info']").re(r'出版社:</span> (.+)<br>\n')[0].strip()
            except:
                item["press"] = "无"
            #出版年
            try:
                item["date"] = response.xpath("//div[@id='info']").re(r'出版年:</span> (.+)<br>\n')[0].strip()
            except:
                item["date"] = "无"
            #页数
            try:
                page_str = response.xpath("//div[@id='info']").re(r'页数:</span> (.+)<br>\n')[0].strip()
                item["page"] = int(re.findall(r'\d+', page_str)[0])
            except:
                item["page"] = "无"
            #定价
            try:
                item["price"] = response.xpath("//div[@id='info']").re(r'定价:</span> (.+)<br>\n')[0].strip()
            except:
                item["price"] = "无"
            #ISBN
            try:
                item["ISBN"] = response.xpath("//div[@id='info']").re(r'ISBN:</span> (.+)<br>\n')[0].strip()
            except:
                item["ISBN"] = "无"
            # 豆瓣评分

            if len(response.xpath("//div[@class='rating_self clearfix']/strong/text()").extract()[0].strip()) > 0:
                item["score"] = float(response.xpath("//div[@class='rating_self clearfix']/strong/text()").extract()[0].strip())
            else:
                item["score"] = "评价人数不足"

            # 内容简介

            if len(response.xpath('//span[@class="all hidden"]/div/div[@class="intro"]/p')) > 0:
                contents = response.xpath('//span[@class="all hidden"]/div/div[@class="intro"]/p/text()').extract()
                item["content_description"] = "\n".join(content.strip() for content in contents)
            elif len(response.xpath('//div[@id="link-report"]/div/div[@class="intro"]/p')) > 0:
                contents = response.xpath('//div[@id="link-report"]/div/div[@class="intro"]/p/text()').extract()
                item["content_description"] = "\n".join(content.strip() for content in contents)
            else:
                item["content_description"] = "无"
            # 作者简介

            profiles_tag = response.xpath('//div[@class="intro"]')[-1]
            profiles = profiles_tag.xpath('p/text()').extract()
            if len(profiles) > 0:
                item["author_profile"] = "\n".join(profile.strip() for profile in profiles)
            else:
                item["author_profile"] = "无"

            # 详情页链接
            item["link"] = response.url

            return item

这里主要注意一下,cookies的使用,如果不用cookie的话,很容易被ban,或者你也可以选择使用ip代理;只要不被ban就行;
其他的部分,代码里有注释,这里我就不解释了;
3、数据存储部分:
pipelines.py

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import pymongo
from scrapy.conf import settings
from scrapy.exceptions import DropItem
from scrapy import log


class DoubanbookPipeline(object):
    def __init__(self):
        connection = pymongo.MongoClient(
            settings['MONGODB_SERVER'],
            settings['MONGODB_PORT']
        )
        db = connection[settings['MONGODB_DB']]
        self.collection = db[settings['MONGODB_COLLECTION']]
    def process_item(self, item, spider):
        valid = True
        for data in item:
            if not data:
                valid = False
                raise DropItem("Missing {0}!".format(data))
        if valid:
            self.collection.insert(dict(item))
            log.msg("Question added to MongoDB database!",
                    level=log.DEBUG, spider=spider)
        return item

这里我是选择存储到pymongo,其他数据库都行,看自己的选择了;
4、设置:
settings.py

# -*- coding: utf-8 -*-
import random
from useragent import Agent

# Scrapy settings for DoubanBook project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     http://doc.scrapy.org/en/latest/topics/settings.html
#     http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
#     http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html

BOT_NAME = 'DoubanBook'

SPIDER_MODULES = ['DoubanBook.spiders']
NEWSPIDER_MODULE = 'DoubanBook.spiders'

ITEM_PIPELINES = {
    'DoubanBook.pipelines.DoubanbookPipeline': 300,
}

MONGODB_SERVER = 'localhost'
MONGODB_PORT = 27017
MONGODB_DB = 'douban'
MONGODB_COLLECTION = 'book_数据分析'

# Crawl responsibly by identifying yourself (and your website) on the user-agent


USER_AGENT = '%s' % random.choice(Agent.user_agent)
# USER_AGENT = 'DoubanBook (+http://www.yourdomain.com)'

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 100

# Retry many times since proxies often fail
RETRY_TIMES = 10
# Retry on most error codes since proxies fail for different reasons
RETRY_HTTP_CODES = [500, 503, 504, 400, 403, 404, 408]

# Configure a delay for requests for the same website (default: 0)
# See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.2
# The download delay setting will honor only one of:
# CONCURRENT_REQUESTS_PER_DOMAIN = 16
# CONCURRENT_REQUESTS_PER_IP = 16

# Disable cookies (enabled by default)禁止使用cookie
COOKIES_ENABLED = False

运行的结果:

图书的图片
图书详情页的数据

大概爬了1000多本图书,感觉应该是比scrapy.Spider快一点,但是这个还是要看自己的网络、设备等;
爬的过程中有几个url由于请求网络超时而失败,所以可以把超时的时间设稍微长一点;

附赠一些些资源:

Scrapy模拟登陆知乎
CrawlSpider爬取拉勾招聘网

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

推荐阅读更多精彩内容

  • scrapy学习笔记(有示例版) 我的博客 scrapy学习笔记1.使用scrapy1.1创建工程1.2创建爬虫模...
    陈思煜阅读 12,653评论 4 46
  • Spiders Spider类定义了如何爬取某个网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中...
    cnkai阅读 1,487评论 1 4
  • Advanced Web Scraping: Bypassing "403 Forbidden," captcha...
    treelake阅读 51,078评论 8 111
  • scrapy是python最有名的爬虫框架之一,可以很方便的进行web抓取,并且提供了很强的定制型,这里记录简单学...
    bomo阅读 2,085评论 1 11
  • (文: 李远红) 如果你是蝴蝶 我就是那朵韧性的花 任你采撷那甜蜜的汁液 伴你一起嬉戏玩耍 如果你是鱼儿 我就是那...
    李远红阅读 203评论 3 2