scrapy爬蟲框架


scrapy框架是異步處理框架,可配置和可擴展程度非常高,Python中使用最廣泛的爬蟲框架。

安裝

Ubuntu安裝

1、安裝依賴包

  1. sudo apt-get install libffi-dev
  2. sudo apt-get install libssl-dev
  3. sudo apt-get install libxml2-dev
  4. sudo apt-get install python3-dev
  5. sudo apt-get install libxslt1-dev
  6. sudo apt-get install zlib1g-dev
  7. sudo pip3 install -I -U service_identity

2、安裝scrapy框架

  1. sudo pip3 install Scrapy

Windows安裝

  cmd命令行(管理員): python -m pip install Scrapy

Scrapy框架五大組件

  1. 引擎(Engine)      :整個框架核心
  2. 調度器(Scheduler)   :維護請求隊列
  3. 下載器(Downloader)  :獲取響應對象,下載器是基於多線程的
  4. 爬蟲文件(Spider)   :數據解析提取
  5. 項目管道(Pipeline)  :數據入庫處理

下載器中間件(Downloader Middlewares) : 引擎->下載器,包裝請求(隨機代理等)

蜘蛛中間件(Spider Middlewares) : 引擎->爬蟲文件,可修改響應對象屬性

scrapy爬蟲工作流程

爬蟲項目啟動

1、由引擎向爬蟲程序索要第一個要爬取的URL,交給調度器去入隊列

2、調度器處理請求后出隊列,通過下載器中間件交給下載器去下載

3、下載器得到響應對象后,通過蜘蛛中間件交給爬蟲程序

4、爬蟲程序進行數據提取:

  1、數據交給管道文件去入庫處理

  2、對於需要繼續跟進的URL,再次交給調度器入隊列,依次循環

scrapy常用命令

1、創建爬蟲項目  scrapy startproject 項目名

2、創建爬蟲文件  scrapy genspider 爬蟲名 域名

          域名為協議后面的名字

3、運行爬蟲    scrapy crawl 爬蟲名

在cmd窗口運行上面指令后,會在當前文件夾自動創建如下目錄結構。

scrapy項目目錄結構

Baidu                   # 項目文件夾
├── Baidu               # 項目目錄
│   ├── items.py        # 定義數據結構
│   ├── middlewares.py    # 中間件
│   ├── pipelines.py     # 數據處理
│   ├── settings.py      # 全局配置
│   └── spiders
│       ├── baidu.py    # 爬蟲文件
└── scrapy.cfg           # 項目基本配置文件

全局配置文件settings.py詳解

1、定義User-Agent

  USER_AGENT = 'Mozilla/5.0'

2、是否遵循robots協議,一定要設置為False

  ROBOTSTXT_OBEY = False

3、最大並發量,默認為16

  CONCURRENT_REQUESTS = 32

4、下載延遲時間

  DOWNLOAD_DELAY = 1

5、請求頭,此處也可以添加User-Agent

  DEFAULT_REQUEST_HEADERS={}

6、項目管道,運行管道函數

  ITEM_PIPELINES={

  '項目目錄名.pipelines.類名':300

  }

創建爬蟲項目步驟

  1. 新建項目 :scrapy startproject 項目名
  2. cd 項目文件夾
  3. 新建爬蟲文件 :scrapy genspider 文件名 域名
  4. 明確目標(items.py)
  5. 寫爬蟲程序(文件名.py)
  6. 管道文件(pipelines.py)
  7. 全局配置(settings.py)
  8. 運行爬蟲 :scrapy crawl 爬蟲名

pycharm運行爬蟲項目

1、創建一個腳本文件,比如:begin.py(和scrapy.cfg文件同目錄)

2、begin.py中內容:

from scrapy import cmdline
cmdline.execute('scrapy crawl maoyan'.split())

導入cmd命令行模塊,在python中寫cmd命令,之所以用split()是因為把字符串按空格切割,這樣cmd才能識別是3個參數。

百度

目標:打開百度首頁,把 '百度一下,你就知道' 抓取下來,從終端輸出

實現步驟

1、創建項目Baidu 和 爬蟲文件baidu

1、scrapy startproject Baidu
2、cd Baidu
3、scrapy genspider baidu www.baidu.com

2、編寫爬蟲文件baidu.py,xpath提取數據

# -*- coding: utf-8 -*-
import scrapy


class BaiduSpider(scrapy.Spider):
    name = 'baidu'      # 爬蟲名 : scrapy crawl 爬蟲名
    allowed_domains = ['www.baidu.com']     # 允許爬取的域名
    start_urls = ['http://www.baidu.com/']      # 起始URL地址

    def parse(self, response):
        # response為百度的響應對象,提取"百度一下,你就知道"
        # r_list: [<selector xpath='',data=''>]
        # extract(): ["百度一下,你就知道"]
        # extract_first(): "百度一下,你就知道"
        # 1.6版本后可使用get(): "百度一下,你就知道"
        r_list = response.xpath('/html/head/title/text()').get()

        print('*'*50)
        print(r_list)
        print('*'*50)

3、全局配置settings.py

USER_AGENT = 'Mozilla/5.0'
ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}

或者把USER_AGENT文件寫道頭文件里面

DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    'USER_AGENT':'Mozilla/5.0',
}

4、創建begin.py(和scrapy.cfg同目錄)

from scrapy import cmdline

cmdline.execute('scrapy crawl baidu'.split())

5、啟動爬蟲

直接運行 begin.py 文件即可

貓眼電影案例

目的

  • URL: 百度搜索 -> 貓眼電影 -> 榜單 -> top100榜
  • 爬取內容:電影名稱、電影主演、上映時間

實現步驟

1、創建項目和爬蟲文件

創建爬蟲項目  scrapy startproject Maoyan
        cd Maoyan
創建爬蟲文件  scrapy genspider maoyan maoyan.com

2、定義要爬取的數據結構(items.py)

name = scrapy.Field()
star = scrapy.Field()
time = scrapy.Field()

3、編寫爬蟲文件(maoyan.py)

1、基准xpath,匹配每個電影信息節點對象列表
  dd_list = response.xpath('//dl[@class="board-wrapper"]/dd')
2、for dd in dd_list:
  電影名稱 = dd.xpath('./a/@title')
  電影主演 = dd.xpath('.//p[@class="star"]/text()')
  上映時間 = dd.xpath('.//p[@class="releasetime"]/text()')

代碼實現一

下載速度慢,爬了一頁再爬第二頁,調度器里面只有一個地址。

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


class MaoyanSpider(scrapy.Spider):
    name = 'maoyan'  # 爬蟲名
    allowed_domains = ['maoyan.com']  # 允許爬蟲的域名
    start_urls = ['https://maoyan.com/board/4?offset=0']  # 起始的URL地址
    offset = 0

    def parse(self, response):
        # 給items.py中的類:MaoyanItem(scrapy.Item)實例化
        item = MaoyanItem()

        # 基准xpath,匹配每個電影信息節點對象列表
        dd_list = response.xpath('//dl[@class="board-wrapper"]/dd')
        # 依次遍歷
        for dd in dd_list:
            # [<selector xpath='' data='霸王別姬'>]
            # dd.xpath('')結果為[選擇器1,選擇器2]
            # .extract() 把[選擇器1,選擇器2]所有選擇器序列化為unicode字符串
            # .extract_first() : 取第一個字符串
            # 是在給items.py中那些類變量賦值
            item['name'] = dd.xpath('./a/@title').get().strip()
            item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip()
            item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip()

            # 把item對象交給管道文件處理
            yield item

        # 此方法不推薦,效率低
        self.offset += 10
        if self.offset <= 91:
            url = 'https://maoyan.com/board/4?offset={}'.format(self.offset)
            # 交給調度器入隊列
            yield scrapy.Request(
                url=url,
                callback=self.parse)

代碼實現二,基於下載器是多線程的,把多個地址,一次性的都給調度器,請求指紋,第一個地址爬了兩次

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


class MaoyanSpider(scrapy.Spider):
    name = 'maoyan2'  # 爬蟲名
    allowed_domains = ['maoyan.com']  # 允許爬取的域名
    start_urls = ['https://maoyan.com/board/4?offset=0']  # 起始的URL地址

    def parse(self, response):
        for offset in range(0, 91, 10):
            url = 'https://maoyan.com/board/4?offset={}'.format(offset)
            # 把地址交給調度器入隊列
            yield scrapy.Request(url=url,
                                 callback=self.parse_page)

    def parse_page(self, response):
        # 給items.py中的類:MaoyanItem(scrapy.Item)實例化
        item = MaoyanItem()

        # 基准xpath,匹配每個電影信息節點對象列表
        dd_list = response.xpath('//dl[@class="board-wrapper"]/dd')
        # dd_list : [<element dd at xxx>,<...>]

        for dd in dd_list:
            # [<selector xpath='' data='霸王別姬'>]
            # dd.xpath('')結果為[選擇器1,選擇器2]
            # .extract() 把[選擇器1,選擇器2]所有選擇器序列化為
            # unicode字符串
            # .extract_first() : 取第一個字符串
            # 是在給items.py中那些類變量賦值
            item['name'] = dd.xpath('./a/@title').get().strip()
            item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip()
            item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip()

            # 把item對象交給管道文件處理
            yield item

代碼實現三

# 重寫start_requests()方法,直接把多個地址都交給調度器去處理
import scrapy
from ..items import MaoyanItem


class MaoyanSpider(scrapy.Spider):
    name = 'maoyan3'  # 爬蟲名
    allowed_domains = ['maoyan.com']  # 允許爬取的域名

    # 去掉start_urls變量

    # 重寫start_requests()方法,把所有URL地址都交給調度器
# 去掉start_urls
def start_requests(self): for offset in range(0, 91, 10): url = 'https://maoyan.com/board/4?offset={}'.format(offset) yield scrapy.Request(url=url, callback=self.parse) # 把地址交給調度器入隊列 def parse(self, response): item = MaoyanItem() # 給items.py中的類:MaoyanItem(scrapy.Item)實例化 # 基准xpath dd_list = response.xpath('//dl[@class="board-wrapper"]/dd') # 依次遍歷 for dd in dd_list: # [<selector xpath='' data='霸王別姬'>] # dd.xpath('')結果為[選擇器1,選擇器2] # .extract() 把[選擇器1,選擇器2]所有選擇器序列化為 # unicode字符串 # .extract_first() : 取第一個字符串 # 是在給items.py中那些類變量賦值 item['name'] = dd.xpath('./a/@title').get().strip() item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip() item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip() yield item # 把item對象交給pipline管道文件處理

3、定義管道文件(pipelines.py)

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

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import pymysql
from .settings import *


class MaoyanPipeline(object):
    # item: 從爬蟲文件maoyan.py中yield的item數據
    def process_item(self, item, spider):
        print(item['name'], item['time'], item['star'])

        return item


# 新建自定義管道 - 存入MySQL數據庫
class MaoyanMysqlPipeline(object):
    # 爬蟲項目開始運行時執行此函數
    def open_spider(self, spider):
        print('我是open_spider函數輸出')
        # 一般用於建立數據庫連接
        self.db = pymysql.connect(
            host=MYSQL_HOST,
            user=MYSQL_USER,
            password=MYSQL_PWD,
            database=MYSQL_DB,
            charset=MYSQL_CHAR)
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        # 因為execute()的第二個參數為列表
        L = [item['name'].strip(),
             item['star'].strip(),
             item['time'].strip()]
        self.cursor.execute('insert into filmtab values(%s,%s,%s)', L)
        self.db.commit()  # 提交到數據庫

        return item

    # 爬蟲項目結束時執行此函數,只執行一次
    def close_spider(self, spider):
        print('我是close_spider函數輸出')
        # 一般用於斷開數據庫連接
        self.cursor.close()
        self.db.close()

5、全局配置文件(settings.py)

ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    '’USER_AGENT' = 'Mozilla/5.0'
}
ITEM_PIPELINES = {
# 300表示優先級(1-1000),數字越小,優先級越高
'Maoyan.pipelines.MaoyanPipeline': 300, 'Maoyan.pipelines.MaoyanMysqlPipeline': 200}

6、創建並運行文件(begin.py)

from scrapy import cmdline
cmdline.execute('scrapy crawl maoyan'.split())

爬蟲項目啟動方式

方式一

從爬蟲文件(spider)的start_urls變量中遍歷URL地址,把下載器返回的響應對象(response)交給爬蟲文件的parse()函數處理

# start_urls = ['http://www.baidu.com/']

方式二

重寫start_requests()方法,從此方法中獲取URL,交給指定的callback解析函數處理

1、去掉start_urls變量

2、def start_requests(self):

     # 生成要爬取的URL地址,利用scrapy.Request()方法交給調度器 **

知識點匯總

response.xpath('')調用方法

結果:列表,元素為選擇器 ['<selector xpath='' data='A'>]

.extract() :提取文本內容,序列化列表中所有選擇器為Unicode字符串 ['A','B','C']

.extract_first() 或者 get() :獲取列表中第1個序列化的元素(字符串)

.get():提取列表中第1個文本內容

response.text:獲取響應內容

response.body:獲取bytes數據類型

response.xpath('')

pipelines.py中必須由1個函數叫process_item

def process_item(self,item,spider):
    return item ( * 此處必須返回 item )

日志變量及日志級別(settings.py)

# 日志相關變量

LOG_LEVEL = ''

LOG_LEVEL = 'INFO'  # 表示終端只顯示INFO和INF日志級別以上的信息,DEBUG就不會顯示了

LOG_FILE :      本來應該輸出在終端的信息,寫入到了log日志文件中

LOG_FILE = '文件名.log'

 

# 日志級別

5 CRITICAL :嚴重錯誤

4 ERROR    :普通錯誤

3 WARNING  :警告

2 INFO     :一般信息

1 DEBUG    :調試信息

settings.py常用變量

LOG_LEVEL = ''              # 1、設置日志級別
LOG_FILE = ''               # 2、保存到日志文件(不在終端輸出)
FEED_EXPORT_ENCODING = ''   # 3、設置數據導出編碼(主要針對於json文件)
IMAGES_STORE = '路徑'        # 4、非結構化數據存儲路徑
USER_AGENT = ''             # 5、設置User-Agent
CONCURRENT_REQUESTS = 32    # 6、設置最大並發數(默認為16)

# 7、下載延遲時間(每隔多長時間請求一個網頁)
# DOWNLOAD_DELAY 會影響 CONCURRENT_REQUESTS,不能使並發顯現
# 有CONCURRENT_REQUESTS,沒有DOWNLOAD_DELAY: 服務器會在同一時間收到大量的請求
# 有CONCURRENT_REQUESTS,有DOWNLOAD_DELAY 時,服務器不會在同一時間收到大量的請求
DOWNLOAD_DELAY = 3

DEFAULT_REQUEST_HEADERS = {}    # 8、請求頭
ITEM_PIPELINES = {}             # 9、添加項目管道
DOWNLOADER_MIDDLEWARES = {}     # 10、添加下載器中間件

 

管道處理數據流程

1、在爬蟲文件中為items.py中類做實例化,用爬下來的數據給對象賦值

from ..items import MaoyanItem

item = MaoyanItem()

item['name'] = xxx

2、管道文件(pipelines.py)
3、開啟管道(settings.py)
ITEM_PIPELINES = { '項目目錄名.pipelines.類名':優先級 }

優先級1-1000,數字越小優先級越高

scrapy.Request()參數

1、url

2、callback

3、meta:傳遞數據,定義代理

數據持久化存儲(MySQL)

實現步驟

1、在setting.py中定義MYSQL相關變量

# 定義MySQL相關變量
MYSQL_HOST = '127.0.0.1'
MYSQL_USER = 'root'
MYSQL_PWD = '123456'
MYSQL_DB = 'maoyandb'
MYSQL_CHAR = 'utf8'

2、pipelines.py中新建管道類,並導入settings模塊from .settings import *

# 新建自定義管道 - 存入MySQL數據庫
class MaoyanMysqlPipeline(object):
    # 爬蟲程序啟動時,只執行1次,一般用於數據庫連接
    def open_spider(self, spider):
        print('我是open_spider函數輸出')
        # 一般用於建立數據庫連接
        self.db = pymysql.connect(
            host=MYSQL_HOST,
            user=MYSQL_USER,
            password=MYSQL_PWD,
            database=MYSQL_DB,
            charset=MYSQL_CHAR)
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        # 用於處理爬取的item數據,這個函數一定要有
        # 因為execute()的第二個參數為列表
        L = [item['name'].strip(),
             item['star'].strip(),
             item['time'].strip()]
        self.cursor.execute('insert into filmtab values(%s,%s,%s)', L)
        self.db.commit()    # 提交到數據庫

        return item

    # 爬蟲項目結束時執行此函數,只執行一次,一般用於斷開數據庫連接
    def close_spider(self, spider):
        print('我是close_spider函數輸出')
        # 一般用於斷開數據庫連接
        self.cursor.close()
        self.db.close()

注意 :process_item() 函數中一定要 return item

3、settings.py中添加此管道

ITEM_PIPELINES = {
    'Maoyan.pipelines.MaoyanPipeline': 300,
    'Maoyan.pipelines.MaoyanMysqlPipeline': 200  # 數據庫的管道
 }

注意 :process_item() 函數中一定要 return item,因為第一個管道返回的item會繼續交由下一個管道處理,否則返回並傳入下一個管道的值為None

 

保存為csv、json文件

scrapy crawl maoyan -o maoyan.csv
scrapy crawl maoyan -o maoyan.json

# 在存json文件的時候,要在setting.py設置到處編碼 FEED_EXPORT_ENCODING = 'utf-8'

盜墓筆記小說抓取案例(三級頁面)

目標

# 抓取目標網站中盜墓筆記1-8中所有章節的所有小說的具體內容,保存到本地文件
1、網址 :http://www.daomubiji.com/

准備工作xpath

1、一級頁面xpath(此處響應做了處理):

  盜墓筆記1-8的鏈接://ul[@class="sub-menu"]/li/a/@href

2、二級頁面xpath:/html/body/section/div[2]/div/article

  基准xpath ://article

  鏈接:./a/@href

  標題:./a/text()  # 七星魯王 第一章 血屍

3、三級頁面xpath:

  response.xpath('//article[@class="article-content"]//p/text()').extract()

項目實現

1、創建項目及爬蟲文件

創建項目 :scrapy startproject Daomu
創建爬蟲 :scrapy genspider daomu www.daomubiji.com

2、定義要爬取的數據結構(把數據交給管道)items.py

import scrapy
​
class DaomuItem(scrapy.Item):
    juan_name = scrapy.Field()    # 卷名
    zh_num = scrapy.Field()       # 章節數
    zh_name = scrapy.Field()      # 章節名
    zh_link = scrapy.Field()      # 章節鏈接
    zh_content = scrapy.Field()   # 小說內容

3、爬蟲文件實現數據抓取 daomu.py

# -*- coding: utf-8 -*-
import scrapy
from ..items import DaomuItem
​
class DaomuSpider(scrapy.Spider):
    name = 'daomu'
    allowed_domains = ['www.daomubiji.com']
    start_urls = ['http://www.daomubiji.com/']
​
    # 解析一級頁面,提取 盜墓筆記1 2 3 ... 鏈接
    def parse(self, response):
        one_link_list = response.xpath('//ul[@class="sub-menu"]/li/a/@href').extract()
        print(one_link_list)
        # 把鏈接交給調度器入隊列
        for one_link in one_link_list:
            yield scrapy.Request(url=one_link, callback=self.parse_two_link, dont_filter=True)
​
    # 解析二級頁面
    def parse_two_link(self,response):
        # 基准xpath,匹配所有章節對象列表
        article_list = response.xpath('/html/body/section/div[2]/div/article')
        # 依次獲取每個章節信息
        for article in article_list:
            # 創建item對象
            item = DaomuItem()
            info = article.xpath('./a/text()').extract_first().split()
            # info : ['七星魯王','第一章','血屍']
            item['juan_name'] = info[0]
            item['zh_num'] = info[1]
            item['zh_name'] = info[2]
            item['zh_link'] = article.xpath('./a/@href').extract_first()
            # 把章節鏈接交給調度器
            yield scrapy.Request(
                url=item['zh_link'],
                # 把item傳遞到下一個解析函數
                meta={'item':item},
                callback=self.parse_three_link,
                dont_filter=True
            )
​
    # 解析三級頁面
    def parse_three_link(self,response):
        # 獲取上一個函數傳遞過來的item對象
        item = response.meta['item']
        # 獲取小說內容
        # ['段落1','段落2','段落3',....]
        item['zh_content'] = '\n'.join(response.xpath(
          '//article[@class="article-content"]//p/text()'
        ).extract())

​        # 所有的數據都爬完了,再yield
        yield item
​
        # '\n'.join(['第一段','第二段','第三段'])    

4、管道文件實現數據處理pipline.py

# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
​
​
class DaomuPipeline(object):
    def process_item(self, item, spider):
        filename = '/home/tarena/aid1902/{}-{}-{}.txt'.format(
            item['juan_name'],
            item['zh_num'],
            item['zh_name']
        )
​
        f = open(filename,'w')
        f.write(item['zh_content'])
        f.close()
        return item

5、setting

  打開通道

騰訊招聘

MySQL數據庫--建庫建表

create database tencentdb charset utf8;
use tencentdb;
create table tencenttab(
        name varchar(100),
        type varchar(100),
        duty varchar(5000),
        requirement varchar(5000)
        )charset=utf8;

1、創建項目+爬蟲文件

scrapy startproject Tencent
cd Tencent
scrapy genspider tencent hr.tencent.com

2、定義爬取的數據結構 items.py

job_name = scrapy.Field()
job_type = scrapy.Field()    # 類別
job_duty = scrapy.Field()    # 職責
job_require = scrapy.Field()    # 要求
job_address = scrapy.Field()    # 地址

3、爬蟲文件

class TencentSpider(scrapy.Spider):
    name = 'tencent'
    allowed_domains = ['careers.tencent.com']
    one_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1563912271089&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
    two_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1563912374645&postId={}&language=zh-cn'
    # 1. 去掉start_urls
    # 2. 重新start_requests()方法
    def start_requests(self):
        total_page = self.get_total_page()
        for page_index in range(1,total_page):
            url = self.one_url.format(page_index)
            yield scrapy.Request(
                url = url,
                callback = self.parse_one
            )
​
    # 獲取總頁數
    def get_total_page(self):
        url = self.one_url.format(1)
        html = requests.get(url=url).json()
        total_page = int(html['Data']['Count']) // 10 + 1return total_page
​
    # 解析一級頁面函數
    def parse_one(self,response):
        html = json.loads(response.text)
        for job in html['Data']['Posts']:
            item = TencentItem()
            # postId: 拼接二級頁面的地址
            post_id = job['PostId']
            two_url = self.two_url.format(post_id)
            # 交給調度器
            yield scrapy.Request(
                url = two_url,
                meta = {'item':item},
                callback = self.parse_two_page
            )
​
    def parse_two_page(self,response):
        item = response.meta['item']
        html = json.loads(response.text)
        item['job_name'] = html['Data']['RecruitPostName']
        item['job_type'] = html['Data']['CategoryName']
        item['job_duty'] = html['Data']['Responsibility']
        item['job_require'] = html['Data']['Responsibility']
        item['job_address'] = html['Data']['LocationName']
​
​
        yield item

4、管道文件

create database tencentdb charset utf8;
use tencentdb;
create table tencenttab(
        job_name varchar(500),
        job_type varchar(100),
        job_duty varchar(1000),
        job_require varchar(1000),
        job_address varchar(100)
        )charset=utf8;

管道文件pipelines實現

import pymysql
class TencentMysqlPipeline(object):
    def open_spider(self,spider):
        self.db = pymysql.connect(
            '127.0.0.1','root','123456','tencentdb',
            charset='utf8'
        )
        self.cursor = self.db.cursor()
​
    def process_item(self,item,spider):
        ins = 'insert into tencenttab values(%s,%s,%s,%s,%s)'
        job_list = [
            item['job_name'],item['job_type'],item['job_duty'],
            item['job_require'],item['job_address']
        ]
        self.cursor.execute(ins,job_list)
        self.db.commit()
        return item
​
    def close_spider(self,spider):
        self.cursor.close()
        self.db.close()

5、settings.py

定義常用變量,添加管道即可

圖片管道(360圖片抓取案例)

目標:www.so.com -> 圖片 -> 美女

抓取網絡數據包

2、F12抓包,抓取到json地址 和 查詢參數(QueryString)
     url = 'http://image.so.com/zj?ch=beauty&sn={}&listtype=new&temp=1'.format(str(sn))
     ch: beauty
     sn: 90
     listtype: new
     temp: 1

項目實現

1、創建爬蟲項目和爬蟲文件

scrapy startproject So
cd So
scrapy genspider so image.so.com

2、定義要爬取的數據結構(items.py)

img_link = scrapy.Field()

3、爬蟲文件實現圖片鏈接抓取

# -*- coding: utf-8 -*-
import scrapy
import json
from ..items import SoItem
​
class SoSpider(scrapy.Spider):
    name = 'so'
    allowed_domains = ['image.so.com']
​
    # 重寫Spider類中的start_requests方法
    # 爬蟲程序啟動時執行此方法,不去找start_urls
    def start_requests(self):
        for page in range(5):
            url = 'http://image.so.com/zj?ch=beauty&sn={}&listtype=new&temp=1'.format(str(page*30))
            # 把url地址入隊列
            yield scrapy.Request(
                url = url,
                callback = self.parse_img
            )
​
    def parse_img(self, response):
        html = json.loads(response.text)
​
        for img in html['list']:
            item = SoItem()
            # 圖片鏈接
            item['img_link'] = img['qhimg_url']
​
            yield item

4、管道文件(pipelines.py)

from scrapy.pipelines.images import ImagesPipeline
import scrapy
​
class SoPipeline(ImagesPipeline):
    # 重寫get_media_requests方法
    def get_media_requests(self, item, info):
        yield scrapy.Request(item['img_link'])

5、設置settings.py

IMAGES_STORE = '/home/tarena/images/'

6、創建run.py運行爬蟲

scrapy shell的使用

基本使用

  1. scrapy shell URL地址
  2. request.headers :請求頭(字典)
  3. reqeust.meta    :item數據傳遞,定義代理(字典)
  4. response.text    :字符串
  5. response.body    :bytes
  6. response.xpath('')

scrapy.Request()

  1. url
  2. callback
  3. headers
  4. meta :傳遞數據,定義代理
  5. dont_filter :是否忽略域組限制,默認False檢查域組限制allowed_domains['']

設置中間件(隨機User-Agent)

少量User-Agent切換

方法一

# settings.py
USER_AGENT = ''
DEFAULT_REQUEST_HEADERS = {}

方法二

# spider
yield scrapy.Request(url,callback=函數名,headers={})

大量User-Agent切換(中間件)

middlewares.py設置中間件

1、獲取User-Agent

  # 方法1 :新建useragents.py,存放大量User-Agent,random模塊隨機切換

  # 方法2 :安裝fake_useragent模塊(sudo pip3 install fack_useragent)

from fake_useragent import UserAgent

ua_obj = UserAgent()
ua = ua_obj.random

2、middlewares.py新建中間件類,攔截傳給下載器的請求內容

class RandomUseragentMiddleware(object):
    def process_request(self,reuqest,spider):
        ua = UserAgent()
        request.headers['User-Agent'] = ua.random    

3、settings.py添加此下載器中間件

DOWNLOADER_MIDDLEWARES = {
    'Baidu.middlewares.TestDownloaderMiddleware': 543,
    'Baidu.middlewares.RandomUaDownloaderMiddleware': 300,
    'Baidu.middlewares.TestRandomProxyMiddleware': 400,
}

設置中間件(隨機代理)

import random
from fake_useragent import UserAgent


# 隨機User-Agent下載器中間件
class RandomUaDownloaderMiddleware(object):
    def process_request(self, request, spider):
        # 給每一個攔截下來的請求包裝隨機User-Agent
        ua = UserAgent()
        useragent = ua.random
        # request.headers: 字典
        request.headers['User-Agent'] = useragent

        print('我是中間件:', useragent)  # 測試

proxy_list = ['http://1.1.1.1:1111', 'http://2.2.2.2:2222']

# 隨機代理IP下載器中間件
class TestRandomProxyMiddleware(object):
    def process_request(self, request, spider):
        proxy = random.choice(proxy_list)  # 1. 隨機選擇並定義好代理
        request.meta['proxy'] = proxy  # 2. 如何包裝
        print('我是中間件2:', proxy)  # 測試

    # 處理異常,一旦代理不能用,則返回請求再次執行下載器中間件,把請求扔回調度器
    def process_exception(self, request, exception, spider):
        return request

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM