scrapy連接MySQL數據庫爬取英雄聯盟英雄傳記

作爲一位對聯盟遊戲的愛好者,學習爬蟲的時候也以這款遊戲作爲對象。

這個項目使用的python版本:3.6.0,scrapy使用的版本:1.11。參照這篇博客即便是不會爬蟲的小白也可以帶你做出一個完整的scrapy項目。廢話不多說現在就開始吧。

這裏是github地址:GitHub

第一步:新建一個scrapy項目

scrapy startproject LOL

使用Windows PowerShell 執行這條命令,將會在當前的路徑下新建一個LOL項目。出現一個LOL文件夾,LOL的目錄結構如下:

LOL--LOL--__pycache__

    |         |  --spiders--__pycache__

    |         |               |--__init__.py

    |         |  --__init__.py

    |         |  --items.py

    |         |  --middlewares.py

    |         |  --pipelines.py

    |         |  --setting.py

    |--scrapy.cfg

清楚目錄結構後簡單的介紹一下文件的作用:

  1. spiders文件夾 就是放你寫的小爬蟲的。
  2. items.py文件 Item 是保存爬取到的數據的容器;其使用方法和python字典類似, 並且提供了額外保護機制來避免拼寫錯誤導致的未定義字段錯誤。類似在ORM中做的一樣,您可以通過創建一個 scrapy.Item 類, 並且定義類型爲 scrapy.Field 的類屬性來定義一個Item。


  3. middlewares.py文件 在我們爬蟲的時候用到的中間件。

  4. pipelines.py文件 管道。

  5. setting.py文件 spider的配置文件。

第二步:開始寫我們的爬蟲項目

1.Spiders

首先是我們的爬蟲spiders文件。寫一個繼承scrapy.Spider的爬蟲LOLSpider。

import scrapy
from LOL.items import LolItem
import re

class LOLSpider(scrapy.Spider):
    def get_start_urls():
        lol_summoner="Aatrox,Ahri,Akali,Alistar,Amumu,Anivia,Annie,Ashe,AurelionSol,Azir,Bard,Blitzcrank,Brand,Braum,Caitlyn,Camille,Cassiopeia,Chogath,Corki,Darius,Diana,Draven,DrMundo,Ekko,Elise,Evelynn,Ezreal,Fiddlesticks,Fiora,Fizz,Galio,Gangplank,Garen,Gnar,Gragas,Graves,Hecarim,Heimerdinger,Illaoi,Irelia,Ivern,Janna,JarvanIV,Jax,Jayce,Jhin,Jinx,Kalista,Karma,Karthus,Kassadin,Katarina,Kayle,Kayn,Kennen,Khazix,Kindred,Kled,KogMaw,Leblanc,LeeSin,Leona,Lissandra,Lucian,Lulu,Lux,Malphite,Malzahar,Maokai,MasterYi,MissFortune,MonkeyKing,Mordekaiser,Morgana,Nami,Nasus,Nautilus,Nidalee,Nocturne,Nunu,Olaf,Orianna,Ornn,Pantheon,Poppy,Quinn,Rakan,Rammus,RekSai,Renekton,Rengar,Riven,Rumble,Ryze,Sejuani,Shaco,Shen,Shyvana,Singed,SionSivir,Skarner,Sona,Soraka,Swain,Syndra,TahmKench,Taliya,Talon,Taric,Teemo,Thresh,Tristana,Trundle,Tryndamere,TwistedFate,Twitch,Udyr,Urgot,Varus,Vayne,Veigar,Velkoz,Vi,Viktor,Vladimir,Volibear,Warwick,Xayah,Xerath,XinZhao,Yasuo,Yorick,Zac,Zed,Ziggs,Zilean,Zoe,Zyra"
        # lol_summoner = "Janna"
        lol_summoner = lol_summoner.split(",")
        start_urls = []
        for summoner in lol_summoner:
            url = "http://yz.lol.qq.com/zh_CN/story/champion/"
            summoner = url + summoner + "/"
            start_urls.append(summoner)
        return start_urls

    name = "lol_hero_story"
    allowed_domains = ["http://yz.lol.qq.com/zh_CN/story/"]
    start_urls = get_start_urls()


    def parse(self, response):
        print("-------------------我進入《英雄聯盟宇宙》界面了--------------------")
        lolItem = LolItem()
        lolItem['name'] = response.xpath('//span[@class="alt__5Tm"]/text()').extract_first() #extract_first()返回第一個元素,無結果返回None
        
        if response.xpath('//p[@id="CatchElement"]/p/text()').extract_first() == None:
        # allStory = response.xpath('//p[@id="CatchElement"]/p/text()').extract() #extract()返回結果爲selector list列表
            summonerHtml = response.text
            summonerHtml = summonerHtml.replace("\r","").replace("\n","").replace("<p>","").replace("</p>","").strip()
            summoner_re = r'showFirstLetterEffect__2JK">(.+?)</div>'
            bbb = re.compile(summoner_re , re.S)
            aaa = bbb.findall(summonerHtml)
            lolItem['story'] = aaa[0]
        else:
            lolItem['story'] = response.xpath('//p[@id="CatchElement"]/text()').extract()
        yield lolItem
        print("-------------------我離開《英雄聯盟宇宙》界面了--------------------")  
        

其中小爬蟲的名字是我們自己定義的,我暫且定義 name = "lol_hero_story" 。allowed_domains = ["http://yz.lol.qq.com/zh_CN/story/"] 。start_urls 是存放將要爬蟲的網址列表。我這裏封裝了一個方法來存放。接下接下來就是我們對結果的解析方法 parse 。我們通過xpath或則css選擇器將數據解析得到自己需要的信息。再將信息存儲再自己定義的Items中。

2.items

items將暫存我們得到的name和story。

# -*- 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 LolItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field() #英雄名
    story = scrapy.Field() #英雄故事
    pass

需要什麼字段在這裏以name = scrapy.Field() 形式直接寫就行。在items.py中我們可以定義多個需要存儲的類似LolItems類。

3.pipelines.py

在這裏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

from twisted.enterprise import adbapi
import MySQLdb
import MySQLdb.cursors
import codecs
import json
from logging import log
import sys

# reload(sys)
# sys.setdefaultencoding('utf-8')

class LolPipeline(object):
    

    @classmethod
    def from_settings(cls,settings):
        '''1、@classmethod聲明一個類方法,而對於平常我們見到的則叫做實例方法。 
           2、類方法的第一個參數cls(class的縮寫,指這個類本身),而實例方法的第一個參數是self,表示該類的一個實例
           3、可以通過類來調用,就像C.f(),相當於java中的靜態方法'''
        dbparams=dict(
            host=settings['MYSQL_HOST'],#讀取settings中的配置
            db=settings['MYSQL_DBNAME'],
            user=settings['MYSQL_USER'],
            passwd=settings['MYSQL_PASSWD'],
            charset='utf8',#編碼要加上,否則可能出現中文亂碼問題
            cursorclass=MySQLdb.cursors.DictCursor,
            use_unicode=False,
        )
        dbpool=adbapi.ConnectionPool('MySQLdb',**dbparams)#**表示將字典擴展爲關鍵字參數,相當於host=xxx,db=yyy....
        return cls(dbpool)#相當於dbpool付給了這個類,self中可以得到
    
    #得到連接池dbpool
    def __init__(self,dbpool):
        self.dbpool=dbpool

    #process_item方法是pipeline默認調用的,進行數據庫操作
    def process_item(self, item, spider):
        query=self.dbpool.runInteraction(self._conditional_update,item)#調用update的方法
        query.addErrback(self._handle_error,item,spider)#調用異常處理方法
        return item

    #寫入數據庫中
    def _conditional_insert(self,tx,item):
        print("---------------這裏是你想知道的tx---------------",tx)
        sql="insert into testpictures(name,url) values(%s,%s)"
        params=(item["name"],item["story"])
        tx.execute(sql,params)

    #錯誤處理方法
    def _handle_error(self, failue, item, spider):
        print (failue)

    #查詢數據庫
    def _conditional_select(self,tx,item):
        print("---------------這裏是測試_conditional_select方法----------------")
        print("---------------這裏是你想知道的tx---------------",tx)
        sql="select count(*) from summoner"
        tx.execute(sql)
        reponse = tx.fetchall()
        print(reponse)
    
    #更新數據庫
    def _conditional_update(self,tx,item):
        print("---------------這裏是執行_conditional_update方法----------------")
        try:
            print("----------------這裏是測試update-------------------")
            sql="update summoner set story='%s' where first_name='%s' or last_name='%s'" %(item["story"],item["name"],item["name"])
            n = tx.execute(sql)
            print(n)
        except expression as identifier:
            raise identifier
        

文本中解釋足夠清楚,在這裏我就不再贅述了。

4.setting

在setting中定義我們需要連接數據庫的變量。

#Mysql數據庫的配置信息
MYSQL_HOST = '111.230.227.159'#騰訊雲公網IP
MYSQL_DBNAME = 'lol'         #數據庫名字,請修改
MYSQL_USER = 'root'             #數據庫賬號,請修改 
MYSQL_PASSWD = '******'         #數據庫密碼,請修改
MYSQL_PORT = 3306               #數據庫端口
CHARSET = "utf8"

將下面這段代碼的註釋去掉這樣我們的pipeline纔會發揮作用。這個文件根據大家的項目名稱不同而不同。

ITEM_PIPELINES = {
   'LOL.pipelines.LolPipeline': 300,
}

順便也吧這個robots協議也給修改了吧。將True改爲False。

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

5.middlewares

一個般的大型網站都有反爬蟲機制,像擼啊擼這樣的大型網站更不用多說了。所以我們應該封裝一下自己,讓自己的小爬蟲像一個正常的瀏覽者。在這裏我們就不在封裝Request headers了,給大家介紹一個模擬軟件。chromedriver,穿上這件聖衣就可以"爲所欲爲"了。生氣

在這裏就不再使用項目中的middlewares.py文件了,我們另建一個文件夾,放入我們自己的mymiddlewares.py。目錄結構如下:

LOL--LOL--__pycache__

    |         |  --spiders--__pycache__

    |         |               |--__init__.py

    |         |  --mymiddlewares--mymiddlewares.py

    |         |  --__init__.py

    |         |  --items.py

    |         |  --middlewares.py

    |         |  --pipelines.py

    |         |  --setting.py

    |--scrapy.cfg

文件內容如下:

from selenium import webdriver
from scrapy.http import HtmlResponse
import time

class zhongjianjian(object):
    def process_request(self, request, spider):
        print("************woshizhongjianjian**************************");
        if spider.name == "lol_hero_story":
            print ("Chromedriver is starting...")
            chromedriver = "E:\chromedriver.exe"
            driver = webdriver.Chrome(chromedriver) #指定使用的瀏覽器
            driver.get(request.url)
            time.sleep(1)
            js = "var q=document.documentElement.scrollTop=10000" 
            driver.execute_script(js) #可執行js,模仿用戶操作。此處爲將頁面拉至最底端。       
            time.sleep(3)
            body = driver.page_source
            print ("訪問"+request.url)
            return HtmlResponse(driver.current_url, body=body, encoding='utf-8', request=request)
        else:
            return None

webdriver中用很多我們需要的聖衣,感興趣的小夥伴們可以自己去研究下。

第三步:啓動我們的爬蟲

啓動爬蟲的命令:scrapy crawl lol_hero_story

另外說一點:數據庫中存儲story的字段類型需要滿足我們的需要,在這裏我用的時text類型。

存儲成功後就是這個樣子了:


最後希望可以和喜愛爬蟲的小夥伴一起相互交流、共同進步。文章中有哪些不足可以提出來一起交流學習呀。大笑

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章