Scrapy使用

Scrapy框架

什么是scrapy

Scrapy是一個為了爬取網(wǎng)站數(shù)據(jù),提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架,我們只需要實現(xiàn)少量的代碼,就能夠快速的抓取。

Scrapy使用了Twisted異步網(wǎng)絡(luò)框架,可以加快我們的下載速度。(Twisted(中文翻譯)扭曲)

入門文檔:https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html

異步和非阻塞的區(qū)別.png

補充:
阻塞和非阻塞指的是拿到結(jié)果之前的狀態(tài)
異步和同步指的是整個過程

功能 解釋 scrapy
Scrapy Engine(引擎) 總指揮:負責(zé)數(shù)據(jù)和信號在不同模塊的傳遞 scrapy已經(jīng)實現(xiàn)
Scheduler(調(diào)度器) 一個隊列,存放引擎發(fā)過來的request請求 scrapy已經(jīng)實現(xiàn)
Downloader(下載器) 下載把引擎發(fā)過來的requests請求,并返回引擎 scrapy已經(jīng)實現(xiàn)
Spider(爬蟲) 處理引擎發(fā)來的response,提取數(shù)據(jù),提取url,并交給引擎 需要手寫
Item Pipeline(管道) 處理引擎?zhèn)鬟^來的數(shù)據(jù),比如存儲 需要手寫
Downloader Middlewares(下載中間件) 可以自定義的下載擴展,比如設(shè)置代理 一般不用手寫
Spider MiddlewaresSpider(中間件) 可以自定義requests請求和進行response過濾 一般不用手寫

文件目錄

scrapy.cfg    #項目的配置文件
items.py      #提取要爬取的字段,字典保存爬取到的數(shù)據(jù)的容器
middlewares   #自定義中間件的地方
pipelines.py  #管道,保存數(shù)據(jù)
settings.py   #項目的設(shè)置文件 設(shè)置文件,UA,啟動管道
spiders       #存儲爬蟲代碼目錄
    itcast.py   #寫爬蟲的文件

爬蟲步驟:

1.創(chuàng)建一個scrapy項目

scrapy startproject mySpider   #mySpider是項目名字

2.生成一個爬蟲

scrapy genspider itcast itcast.cn  #itcast是爬蟲名字,"itcast.cn"限制爬蟲地址,防止爬到其他網(wǎng)站

3.提取數(shù)據(jù)

完善spiders,使用xpath等方法

3.保存數(shù)據(jù)

pipelines中保存數(shù)據(jù)

啟動爬蟲

scrapy crawl 爬蟲名字    #crawl(抓取的意思)

啟動爬蟲不打印日志

scrapy crawl 爬蟲名字 --nolog

run.py啟動爬蟲

from scrapy import cmdline
cmdline.execute("scrapy crawl lagou".split())
Scrapy運行流程

spider內(nèi)容

spider翻頁

# -*- coding: utf-8 -*-
import scrapy
#導(dǎo)入items
from tencent.items import TencentItem

#自定義spider類,繼承自scrapy.Spider
class ItcastSpider(scrapy.Spider):
    name = 'itcast' #爬蟲名字<爬蟲啟動時候使用:scrapy crawl itcast>
    #允許爬取的范圍,防止爬蟲爬到了別的網(wǎng)站
    allowed_domains = ['tencent.com']
    #開始爬取的地址,下載中間件提取網(wǎng)頁數(shù)據(jù)
    start_urls = ['https://hr.tencent.com/position.php']
    #數(shù)據(jù)提取方法,接收下載中間件傳過來的response(響應(yīng))
    def parse(self, response):
        #處理start_url地址對應(yīng)的響應(yīng)
        #提取數(shù)據(jù)
        # reti = response.xpath("http://div[@class='tea_con']//h3/text()").extract()
        # print(reti)

        #分組,[1:-1]切片,不要第一條數(shù)據(jù)
        li_list = response.xpath("http://table[@class="tablelist"]/tr")[1:-1]
        for li in li_list:
            #在item中定義要爬取的字段,以字典形式傳入
            item = TencentItem()
            item["name"] = li.xpath(".//h3/text()").extract_first()
            item["title"] = li.xpath(".//h4/text()").extract_first()
            #yield可以返回request對象,BaseItem(items.py中的類),dict,None
            yield item  #yield傳到pipeline
        #找到下一頁url地址
        next_url = response.xpath('//a[@id="next"]/@href').extract_first()
        #如果url地址的href="地址"不等于javascript:;
        if next_url != "javascript:;":
            next_url = "https://hr.tencent.com/"+ next_url
            #把next_url的地址通過回調(diào)函數(shù)callback交給parse方法處理
            yield scrapy.Request(next_url,callback=self.parse)

提取數(shù)據(jù)
response.xpath('//a[@id="next"]/@href')

body = response.text.replace('\n', '').replace('\r', '').replace('\t', '')
re.findall('<a title=".?" href="(.?)"', body)

從選擇器中提取字符串:

  • extract() 返回一個包含有字符串數(shù)據(jù)的列表
  • extract_first()返回列表中的第一個字符串

注意:

  • spider中的parse方法名不能修改
  • 需要爬取的url地址必須要屬于allow_domain(允許_域)下的連接
  • respone.xpath()返回的是一個含有selector對象的列表

為什么要使用yield?
讓整個函數(shù)變成一個生成器,變成generator(生成器)有什么好處?
每次遍歷的時候挨個讀到內(nèi)存中,不會導(dǎo)致內(nèi)存的占用量瞬間變>高python3中range和python2中的xrange同理

scrapy.Request常用參數(shù)為
callback = xxx:指定傳入的url交給那個解析函數(shù)去處理
meta={"xxx":"xxx"}:實現(xiàn)在不同的解析函數(shù)中傳遞數(shù)據(jù),配合callback用
dont_filter=False:讓scrapy的去重不會過濾當前url,默認開啟url去重
headers:請求頭
cookies:cookies,不能放在headers中,獨立寫出來
method = "GET":請求方式,(GET和POST)

爬取詳細頁和翻頁

# -*- coding: utf-8 -*-
import scrapy
from yangguang.items import YangguangItem

class YgSpider(scrapy.Spider):
    name = 'yg'
    allowed_domains = ['sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0']

    def parse(self, response):
        tr_list = response.xpath("http://div[@class='greyframe']/table[2]/tr/td/table/tr")
        for tr in tr_list:
            item = YangguangItem()
            item["title"] = tr.xpath("./td[2]/a[@class='news14']/@title").extract_first()
            item["href"] = tr.xpath("./td[2]/a[@class='news14']/@href").extract_first()
            item["publish_date"] = tr.xpath("./td[last()]/text()").extract_first()
            #執(zhí)行進入url地址,再把item傳到下面parse_detail,提取詳細頁的內(nèi)容
            yield scrapy.Request(item["href"],callback=self.parse_detail,meta={"item":item})
        #翻頁
        #獲取url地址
        next_url = response.xpath("http://a[text()='>']/@href").extract_first()
        #如果下一頁url地址不為空,進入下一頁連接
        if next_url is not None:
            yield scrapy.Request(next_url,callback=self.parse)

    #處理詳情頁
    def parse_detail(self,response):
        #item接收meta傳過來的item,在item字典里繼續(xù)為item添加內(nèi)容
        item = response.meta["item"]
        #拿到詳細頁的內(nèi)容
        item["content"] = response.xpath("http://div[@class='c1 text14_2']//text()").extract()
        #拿到詳細頁的圖片地址
        item["content_img"] = response.xpath("http://div[@class='c1 text14_2']//img/@src").extract()
        #給圖片前面加上http://wz.sun0769.com
        item["content_img"] = ["http://wz.sun0769.com" + i for i in item["content_img"]]
        #把item傳給pipeline
        yield item

items(存儲爬取字段)

import scrapy
#scrapy.Item是一個字典
class TencentItem(scrapy.Item):
#scrapy.Field()是一個字典
url = scrapy.Field()
name = scrapy.Field()

使用pipeline(管道)

from demo1 import settings
import pymongo

class Demo1Pipeline(object):
    def __init__(self):
        #連接mongodb數(shù)據(jù)庫(數(shù)據(jù)庫地址,端口號,數(shù)據(jù)庫)
        client = pymongo.MongoClient(host=settings.MONGODB_HOST, port=settings.MONGODB_PORT)
        #選擇數(shù)據(jù)庫和集合
        self.db = client[settings.MONGODB_DBNAME][settings.MONGODB_DOCNAME]
    def process_item(self, item, spider):
        data = dict(item)
        self.db.insert(data)

#完成pipeline代碼后,需要在setting中設(shè)置開啟
ITEM_PIPELINES = {
  #開啟管道,可以設(shè)置多個管道,'管道地址數(shù)值':越小越先執(zhí)行
  'mySpider.pipelines.MyspiderPipeline': 300,
}
# MONGODB 主機環(huán)回地址127.0.0.1
MONGODB_HOST = '127.0.0.1'
# 端口號,默認是27017
MONGODB_PORT = 27017
# 設(shè)置數(shù)據(jù)庫名稱
MONGODB_DBNAME = 'DouBan'
# 存放本次數(shù)據(jù)的表名稱
MONGODB_DOCNAME = 'DouBanMovies'

第二種:

class MyspiderPipeline(object):
def __init__(self):
    #連接mongodb數(shù)據(jù)庫(數(shù)據(jù)庫地址,端口號,數(shù)據(jù)庫)
    client = pymongo.MongoClient(host=settings.MONGODB_HOST, port=settings.MONGODB_PORT)
    #選擇數(shù)據(jù)庫和集合
    self.db = client[settings.MONGODB_DBNAME]

    #實現(xiàn)存儲方法,item是spider傳過來的,spider就是自己寫的爬蟲
    def process_item(self, item, spider):
      table = ''
      #通過spider參數(shù),可以針對不同的Spider進行處理
      #spider.name爬蟲的名字
      if spider.name == "itcast":
        #如果爬蟲的名字為itcast執(zhí)行這里面的東西
        table = self.db.表名
        #如果爬蟲的名字為itcast2執(zhí)行這里面的東西
      elif spider.name == "itcast2":
        table = self.db.表名
      table.insert(dict(item))

      #也可以通過item參數(shù),可以針對不同的Item進行處理
      table = ''
      if isinstance(item, 爬蟲名字):
        table = self.db.表名
      table.insert(dict(item))

mysql存儲

from pymysql import connect
import pymysql
class TxPipeline(object):
    def __init__(self):
        self.conn=connect(host='localhost',port=3306,db='txzp',user='root',passwd='root',charset='utf8')
        self.cc = self.conn.cursor()
    def process_item(self, item, spider):
        print(item["title"],item["href"],item["number"],item["time"],item["duty"])
        aa = (item["title"],item["href"],item["number"],item["time"],item["duty"],item["requirement"])
        sql = '''insert into tx values (0,"%s","%s","%s","%s","%s","%s")'''
        self.cc.execute(sql%aa)
        self.conn.commit()#提交
        # self.cc.close()   #關(guān)閉游標會報錯

注意

  • pipeline中process_item方法名不能修改,修改會報錯
  • pipeline(管道)可以有多個
  • 設(shè)置了pipelines必須開啟管道,權(quán)重越小優(yōu)先級越高

為什么需要多個pipeline:

  • 可能會有多個spider,不同的pipeline處理不同的item的內(nèi)容
  • 一個spider的內(nèi)容可能要做不同的操作,比如存入不同的數(shù)據(jù)庫中

簡單設(shè)置LOG(日志)

為了讓我們自己希望輸出到終端的內(nèi)容能容易看一些:
我們可以在setting中設(shè)置log級別
在setting中添加一行(全部大寫):

LOG LEVEL="WARNING"

默認終端顯示的是debug級別的log信息

logging模塊的使用

scrapy中使用logging

#settings中設(shè)置
LOG_LEVEL=“WARNING”
LOG_FILE="./a.log"  #設(shè)置日志保存的位置,設(shè)置會后終端不會顯示日志內(nèi)容
#打印logging日志
import logging
#實例化logging,顯示運行文件的名字,不寫不會顯示運行文件的目錄
logging = logging.getLogger(__name__)
#日志輸出打印
logging.warning(item)

#打印內(nèi)容(日志創(chuàng)建時間,運行文件的目錄,日志級別,打印的內(nèi)容)
2018-10-31 15:25:57 [mySpider.pipelines] WARNING: {'name': '胡老師', 'title': '高級講師'}

普通項目中使用logging
具體參數(shù)信息:https://www.cnblogs.com/bjdxy/archive/2013/04/12/3016820.html

#a.py文件

import logging
#level: 設(shè)置日志級別,默認為logging.WARNING
logging.basicConfig(level=logging.INFO,
                    format=
                        #日志的時間
                        '%(asctime)s'
                        #日志級別名稱 : 當前行號
                        ' %(levelname)s [%(filename)s : %(lineno)d ]'
                        #日志信息
                        ' : %(message)s'
                        #指定時間格式
                        , datefmt='[%Y/%m/%d %H:%M:%S]')
#實例化logging,顯示當前運行文件的名字,不寫不會顯示運行文件的目錄
logging=logging.getLogger(__name__)

if __name__ == '__main__':
    #日志級別打印信息
    logging.info("this is a info log")

b.py文件使用a.py文件的logging(日志)

#b.py文件

from a import logging #導(dǎo)入a.py中的實例logging

if __name__ == '__main__':
#warning級別大于info也可以打印,debug級別小于info,不可以打印
logger.warning("this is log b")

日志級別:

  • debug   #調(diào)試
  • info     #正常信息
  • warning  #警告
  • error   #錯誤

如果設(shè)置日志級別為info,warning級別比info大,warning也可以打印,debug比info小不可以打印
如果設(shè)置日志級別為warning,info和debug都比warning小,不可以打印

把數(shù)據(jù)保存到mongodb中

#導(dǎo)入mongodb的包
from pymongo import MongoClient
#實例化client,建立連接
client = MongoClient(host='127.0.0.1',port = 27017)
#選擇數(shù)據(jù)庫和集合
collection = client["tencent"]["hr"]

class TencentPipeline(object):
    def process_item(self, item, spider):
        #傳過來的數(shù)據(jù)是對象,把item轉(zhuǎn)化為字典
        item = dict(item)
        #把數(shù)據(jù)存入mongodb數(shù)據(jù)庫
        collection.insert(item)
        print(item)
        return item

scrapy shell

Scrapy shell是一個交互終端,我們可以在未啟動spider的情況下嘗試及調(diào)試代碼,也可以用來測試XPath表達式

使用方法:

命令行輸入:
    scrapy shell http://www.itcast.cn/channel/teacher.shtml

常用參數(shù):

response.url:當前響應(yīng)的url地址
response.request.url:當前響應(yīng)對應(yīng)的請求的url地址
response.headers:響應(yīng)頭
response.body:響應(yīng)體,也就是html代碼,默認是byte類型
response.body.decode():變?yōu)樽址愋?response.request.headers:當前響應(yīng)的請求頭
response.xpath("http://h3/text()").extract():調(diào)試xpath,查看xpath可不可以取出數(shù)據(jù)

setting設(shè)置文件

為什么需要配置文件:

  • 配置文件存放一些公共的變量(比如數(shù)據(jù)庫的地址,賬號密碼等)
  • 方便自己和別人修改
  • 一般用全大寫字母命名變量名SQL_HOST='192.168.0.1'

參考地址:https://blog.csdn.net/u011781521/article/details/70188171

#常見的設(shè)置

#項目名
BOT_NAME = 'yangguang'
#爬蟲位置
SPIDER_MODULES = ['yangguang.spiders']
NEWSPIDER_MODULE = 'yangguang.spiders'
#遵守robots協(xié)議,robots.txt文件
ROBOTSTXT_OBEY = True
#下載延遲,請求前睡3秒
DOWNLOAD_DELAY = 3
# 默認請求頭,不能放瀏覽器標識
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  "Cookie": "rfnl=https://www.guazi.com/sjz/dazhong/; antipas=2192r893U97623019B485050817",
}
#項目管道,保存數(shù)據(jù)
ITEM_PIPELINES = {
   'yangguang.pipelines.YangguangPipeline': 300,
}

spiders文件使用settings的配置屬性

#第一種
self.settings["MONGO_HOST"]
#第二種
self.settings.get("MONGO_HOST")

pipelines文件使用settings的配置屬性

spider.settings.get("MONGO_HOST")

Scrapy中CrawlSpider類

深度爬蟲

#創(chuàng)建CrawlSpider爬蟲,就多加了-t crawl
scrapy genspider -t crawl cf gov.cn

第一種用法:提取內(nèi)容頁和翻頁

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from tengxun.items import TengxunItem


class TxSpider(CrawlSpider):
    name = 'tx'
    allowed_domains = ['hr.tencent.com']
    #第一次請求的url
    start_urls = ['https://hr.tencent.com/position.php']
    #rules自動提取url地址
    rules = (
        # 內(nèi)容頁,交給parse_item處理數(shù)據(jù)
        Rule(LinkExtractor(allow=r'position_detail\.php\?id=\d+&keywords=&tid=0&lid=0'), callback='parse_item'),
        # 翻頁
        Rule(LinkExtractor(allow=r'position\.php\?&start=\d+#a'), follow=True),
    )
    #處理內(nèi)容頁的數(shù)據(jù)
    def parse_item(self, response):
        item = TengxunItem()
        #爬取標題
        item["bt"] = response.xpath('//td[@id="sharetitle"]/text()').extract_first()
        #爬取工作要求
        item["gzyq"] = response.xpath('//div[text()="工作要求:"]/../ul/li/text()').extract()
        yield item

第二種用法:提取標題頁,內(nèi)容,翻頁

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from tengxun.items import TengxunItem

class Tx2Spider(CrawlSpider):
    name = 'tx2'
    allowed_domains = ['hr.tencent.com']
    start_urls = ['https://hr.tencent.com/position.php']

    rules = (
        #翻頁
        Rule(LinkExtractor(allow=r'position\.php\?&start=\d+#a'), callback='parse_item', follow=True),
    )
    #標題頁內(nèi)容
    def parse_item(self, response):
        tr_list = response.xpath('//table[@class="tablelist"]/tr')[1:-1]
        for tr in tr_list:
            item = TengxunItem()
            #爬取標題
            item['bt'] = tr.xpath('./td/a/text()').extract_first()
            #爬取url
            item['url'] = tr.xpath('./td/a/@href').extract_first()
            item['url'] = "https://hr.tencent.com/" + item['url']
            yield scrapy.Request(
                item['url'],
                callback=self.parse_detail,
                meta={"item":item}
            )
    #爬取內(nèi)容
    def parse_detail(self,response):
        item = response.meta['item']
        item['gzyq'] = response.xpath('//div[text()="工作要求:"]/../ul/li/text()').extract()
        yield item

#LinkExtractor 連接提取器,提取url地址
#callback 提取出來的url地址的response會交給callback處理
#follow 當前url地址的響應(yīng)是否重新進過rules來提取url地址
#提取詳細頁的url
#CrawlSpider會自動把url補充完整

Rule的匹配細節(jié)

Rule(LinkExtractor(allow=r'position_detail\.php\?id=\d+&keywords=&tid=0&lid=0'), callback='parse_item'),
#這里把該匹配的東西寫成正則
#?和.別忘了轉(zhuǎn)義\?  \.
#LinkExtractor 連接提取器,提取url地址
#callback 提取出來的url地址的response會交給callback處理
#follow 當前url地址的響應(yīng)是否重新進過rules來提取url地址
#提取詳細頁的url
#CrawlSpider會自動把url補充完整

注意點:

  • 用命令創(chuàng)建一個crawlspider的模板:scrapy genspider-t crawl 爬蟲名字 域名,也可以手動創(chuàng)建
  • CrawiSpider中不能再有以parse為名字的數(shù)據(jù)提取方法,這個方法被CrawlSpider用來實現(xiàn)基礎(chǔ)url提取等功能)
  • 一個Rule對象接收很多參數(shù),首先第一個是包含url規(guī)則的LinkExtractor對象,常用的還有calback(制定滿足規(guī)則的url的解析函數(shù)的字符串)和follow(response中提取的鏈接是否需要跟進)
  • 不指定callback函數(shù)的請求下,如果follow為True,滿足該rule的url還會繼續(xù)被請求
  • 如果多個Rule都滿足某一個url,會從rules中選擇第一個滿足的進行操作

CrawlSpider補充(了解)

LinkExtractor更多常用鏈接

LinkExtractor(allow=r'/web/site0/tab5240/info\d+\.htm')

allow:滿足括號中"正則表達式"的URL會被提取,如果為空,則全部匹配.
deny:滿足括號中"正則表達式"的URL一定不提取(優(yōu)先級高于allow).
allow_domains:會被提取的鏈接的domains.
deny_domains:一定不會被提取鏈接的domains.
restrict_xpaths:使用xpath表達式,和allow共同作用過濾鏈接,級xpath滿足范圍內(nèi)的uri地址會被提取
rule常見參數(shù):

Rule(LinkExtractor(allow=r'/web/site0/tab5240/info\d+\.htm'), callback='parse_item', follow=False),

LinkExtractor:是一個Link Extractor對象,用于定義需要提取的鏈接.
callback:從link_extractor中每獲取到鏈接時,參數(shù)所指定的值作為回調(diào)函數(shù)
follow:是一個布爾(boolean)值,指定了根據(jù)該規(guī)則從response提取的鏈接是否需要跟進.如果callback為None,follow 默認設(shè)置為True,否則默認為False.
process_links:指定該spider中哪個的函數(shù)將會被調(diào)用,從link_extractor中獲取到鏈接列表時將會調(diào)用該函數(shù),該方法主要用來過濾url.
process_request:指定該spider中哪個的函數(shù)將會被調(diào)用,該規(guī)則提取到每個request時都會調(diào)用該函數(shù),用來過濾request

Scrapy分布式爬蟲

Scrapy分布式爬蟲流程

Scrapy_redis之domz

domz相比于之前的spider多了持久化和request去重的功能
domz就是Crawlspider去重和持久化版本
不能分布式
可以分布式的是RedisSpider和RedisCrawlspider

Scrapy redis在scrapy的基礎(chǔ)上實現(xiàn)了更多,更強大的功能,具體體現(xiàn)在:reqeust去重,爬蟲持久化,和輕松實現(xiàn)分布式
官方站點:https://github.com/rmax/scrapy-redis

#spiders文件夾

爬蟲內(nèi)容和自己寫的CrawlSpider沒有任何區(qū)別
settings.py
#寫上下面東西Crawlspider就可以去重了
#還可以持久化爬蟲,關(guān)閉后,在開啟繼續(xù)爬取

DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"  #去重
SCHEDULER = "scrapy_redis.scheduler.Scheduler"  #重寫調(diào)度器(scheduler)
SCHEDULER_PERSIST = True  #不清楚緩存,隊列中的內(nèi)容是否持久保存(開啟后爬蟲關(guān)閉后,下次開啟從關(guān)閉的位置繼續(xù)爬取)

ITEM_PIPELINES = {
    #將數(shù)據(jù)保存到redis中,屏蔽這條命令
    #'scrapy_redis.pipelines.RedisPipeline': 400,
}

#指定redis地址
REDIS_URL = 'redis://127.0.0.1:6379'
#也可以寫成下面形式
#REDIS_HOST = "127.0.0.1"
#REDIS_PORT = 6379

我們執(zhí)行domz的爬蟲,會發(fā)現(xiàn)redis中多了一下三個鍵:

  • dmoz:requests  (zset類型)(待爬取)
    Scheduler隊列,存放的待請求的request對象,獲取的過程是pop操作,即獲取一個會去除一個

  • dmoz:dupefilter  (set)(已爬取)
    指紋集合,存放的是已經(jīng)進入scheduler隊列的request對象的指紋,指紋默認由請求方法,url和請求體組成

  • dmoz:items  (list類型)(item信息)
    存放的獲取到的item信息,在pipeline中開啟RedisPipeline才會存入

Scrapy_redis之RedisSpider

from scrapy_redis.spiders import RedisSpider

#繼承RedisSpider
class MySpider(RedisSpider):
#指定爬蟲名
name='myspider_redis'

#指定redis中start_urls的鍵,
#啟動的時候只需要往對應(yīng)的鍵總存入url地址,不同位置的爬蟲就會來獲取該url
#所以啟動爬蟲的命令分類兩個步驟:
#(1)scrapy crawl myspider_redis(或者scrapy runspider myspider_redis)讓爬蟲就緒
#(2)在redis中輸入lpush myspider:start_urls"http://dmoztools.net/"讓爬蟲從這個ur開始爬取
redis_key ='myspider:start_urls'

#手動指定allow_domain,執(zhí)行爬蟲范圍
#可以不寫
allow_doamin=["dmoztools.net"]

def parse(self, response):
  #普通scrapy框架寫法
  ...

啟動

#爬蟲名字
scrapy runspider myspider
或(2選1)
#蜘蛛文件名字
scrapy runspider myspider.py

redis運行

#redis 添加 鍵:值 "爬取的網(wǎng)址"
redis-c1i lpush guazi:start_urls "http://ww.guazi.com/sjz/dazhong/"

Scrapy_redis之RedisCrawlSpider

from scrapy.spiders import Rule
from scrapy.linkextractors import LinkExtractor
from scrapy_redis.spiders import RedisCrawlSpider

#繼承RedisCrawlSpider
class MyCrawler(RedisCrawlSpider):
#爬蟲名字
name='mycrawler_redis'
#start_url的redis的鍵
redis_key='mycrawler:start_urls'
#手動制定all_domains,可以不寫
allow_domains=["dmoztools.net"]
#和crawl一樣,指定url的過濾規(guī)則
rules=(
  Rule(LinkExtractor(),callback='parse_page',follow=True)

啟動

#爬蟲名字
scrapy runspider myspider
或(2選1)
#蜘蛛文件名字
scrapy runspider myspider.py

redis運行

#redis 添加 鍵:值 "爬取的網(wǎng)址"
redis-c1i lpush guazi:start_urls "http://ww.guazi.com/sjz/dazhong/"

快速啟動爬蟲

from scrapy import cmdline

cmdline.execute("scrapy crawl guazicrawl".split())

# import redis
#
# r=redis.StrictRedis()
# r.lpush("myspider:start_urls",[])

其他參數(shù)

  • 如果抓取的url不完整,沒前面的url,可以使用下面方法
import urllib
a = http://www.baidu.com?123
b = ?456
#在程序中a可以使用response.url(響應(yīng)地址)
#在pycharm中parse顏色會加深,不過沒事
b = urllib.parse.urljoin(a,b)
print("b=%s"%b)
#b=http://www.baidu.com?456

存多個url或其他東西,可以用列表存儲

#比如存圖片連接,一個網(wǎng)頁中有很多圖片連接
item["img_list"] =[]
#extend追加的方式,注意后面用.extract()
item["img_list"].extend(response.xpath('//img[@class="BDE_Image"]/@src').extract())
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容