最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python使用adbapi實(shí)現(xiàn)MySQL數(shù)據(jù)庫(kù)的異步存儲(chǔ)

 更新時(shí)間:2019年03月19日 14:30:27   作者:Wilson_Iceman  
這篇文章主要為大家詳細(xì)介紹了python使用adbapi實(shí)現(xiàn)MySQL數(shù)據(jù)庫(kù)的異步存儲(chǔ),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

之前一直在寫(xiě)有關(guān)scrapy爬蟲(chóng)的事情,今天我們看看使用scrapy如何把爬到的數(shù)據(jù)放在MySQL數(shù)據(jù)庫(kù)中保存。

有關(guān)python操作MySQL數(shù)據(jù)庫(kù)的內(nèi)容,網(wǎng)上已經(jīng)有很多內(nèi)容可以參考了,但都是在同步的操作MySQL數(shù)據(jù)庫(kù)。在數(shù)據(jù)量不大的情況下,這種方法固然可以,但是一旦數(shù)據(jù)量增長(zhǎng)后,MySQL就會(huì)出現(xiàn)崩潰的情況,因?yàn)榫W(wǎng)上爬蟲(chóng)的速度要遠(yuǎn)遠(yuǎn)高過(guò)往數(shù)據(jù)庫(kù)中插入數(shù)據(jù)的速度。為了避免這種情況發(fā)生,我們就需要使用異步的方法來(lái)存儲(chǔ)數(shù)據(jù),爬蟲(chóng)與數(shù)據(jù)存儲(chǔ)互不影響。

為了顯示方便,我們把程序設(shè)計(jì)的簡(jiǎn)單一點(diǎn),只是爬一頁(yè)的數(shù)據(jù)。我們今天選擇伯樂(lè)在線這個(gè)網(wǎng)站來(lái)爬取,只爬取第一頁(yè)的數(shù)據(jù)。

首先我們還是要啟動(dòng)一個(gè)爬蟲(chóng)項(xiàng)目,然后自己建了一個(gè)爬蟲(chóng)的文件jobbole.py。我們先來(lái)看看這個(gè)文件中的代碼

# -*- coding: utf-8 -*-
import io
import sys
import scrapy
import re
import datetime
from scrapy.http import Request
from urllib import parse
from ArticleSpider.items import JobboleArticleItem, ArticleItemLoader
from scrapy.loader import ItemLoader
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
 
class JobboleSpider(scrapy.Spider):
 """docstring for JobboleSpider"""
 name = "jobbole"
 allowed_domain = ["blog.jobbole.com"]
 start_urls = ['http://blog.jobbole.com/all-posts/']
 
 def parse(self, response):
 """
 1.獲取列表頁(yè)中的文章url
 """
 # 解析列表匯中所有文章url并交給scrapy下載器并進(jìn)行解析
 post_nodes = response.css("#archive .floated-thumb .post-thumb a")
 for post_node in post_nodes:
 image_url = post_node.css("img::attr(src)").extract_first("")# 這里取出每篇文章的封面圖,并作為meta傳入Request
 post_url = post_node.css("::attr(href)").extract_first("")
 yield Request(url = parse.urljoin(response.url, post_url), meta = {"front_image_url":image_url}, callback = self.parse_detail)
 
 def parse_detail(self, response):
 article_item = JobboleArticleItem()
 # 通過(guò)ItemLoader加載Item
 # 通過(guò)add_css后的返回值都是list型,所有我們?cè)賗tems.py要進(jìn)行處理
 item_loader = ArticleItemLoader(item = JobboleArticleItem(), response = response)
 item_loader.add_css("title", ".entry-header h1::text")
 item_loader.add_value("url", response.url)
 # item_loader.add_value("url_object_id", get_md5(response.url))
 item_loader.add_value("url_object_id", response.url)
 item_loader.add_css("create_date", "p.entry-meta-hide-on-mobile::text")
 item_loader.add_value("front_image_url", [front_image_url])
 item_loader.add_css("praise_nums", ".vote-post-up h10::text")
 item_loader.add_css("comment_nums", "a[href='#article-comment'] span::text")
 item_loader.add_css("fav_nums", ".bookmark-btn::text")
 item_loader.add_css("tags", "p.entry-meta-hide-on-mobile a::text")
 item_loader.add_css("content", "div.entry")
 
 article_item = item_loader.load_item()
 print(article_item["tags"])
 
 yield article_item
 pass

這里我把代碼進(jìn)行了簡(jiǎn)化,首先對(duì)列表頁(yè)發(fā)出請(qǐng)求,這里只爬取一頁(yè)數(shù)據(jù),然后分析每一頁(yè)的url,并且交給scrapy對(duì)每一個(gè)url進(jìn)行請(qǐng)求,得到每篇文章的詳情頁(yè),把詳情頁(yè)的相關(guān)內(nèi)容放在MySQL數(shù)據(jù)庫(kù)中。
這里使用itemloader來(lái)進(jìn)行頁(yè)面的解析,這樣解析有個(gè)最大的好處就是可以把解析規(guī)則存放在數(shù)據(jù)庫(kù)中,實(shí)現(xiàn)對(duì)解析規(guī)則的動(dòng)態(tài)加載。但是要注意一點(diǎn)是使用itemloader中css方式和xpath方式得到的數(shù)據(jù)都是list型,因此還需要在items.py中再對(duì)相對(duì)應(yīng)的數(shù)據(jù)進(jìn)行處理。

接下來(lái)我們就來(lái)看看items.py是如何處理list數(shù)據(jù)的。

# -*- coding: utf-8 -*-
 
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import datetime
import re
 
 
import scrapy
from scrapy.loader import ItemLoader
from scrapy.loader.processors import MapCompose, TakeFirst,Join
from ArticleSpider.utils.common import get_md5
 
 
def convert_date(value):
 try:
 create_date = datetime.datetime.strptime(create_date, "%Y/%m/%d").date()
 except Exception as e:
 create_date = datetime.datetime.now().date()
 return create_date
 
def get_nums(value):
 match_re = re.match(".*?(\d+).*", value)
 if match_re:
 nums = int(match_re.group(1))
 else:
 nums = 0
 
 return nums
 
def remove_comment_tags(value):
 # 去掉tags中的評(píng)論內(nèi)容
 if "評(píng)論" in value:
 # 這里做了修改,如果返回"",則在list中仍然會(huì)占位,會(huì)變成類似于["程序員",,"解鎖"]這樣
 # return ""
 return None 
 else:
 return value
 
def return_value(value):
 return 
 
class ArticleItemLoader(ItemLoader):
 """docstring for AriticleItemLoader"""
 # 自定義ItemLoader
 default_output_processor = TakeFirst()
 
class ArticlespiderItem(scrapy.Item):
 # define the fields for your item here like:
 # name = scrapy.Field()
 pass
 
class JobboleArticleItem(scrapy.Item):
 """docstring for ArticlespiderItem"""
 title = scrapy.Field()
 create_date = scrapy.Field(
 input_processor = MapCompose(convert_date)
 )
 url = scrapy.Field()
 url_object_id = scrapy.Field(
 output_processor = MapCompose(get_md5)
 )
 # 這里注意front_image_url還是一個(gè)list,在進(jìn)行sql語(yǔ)句時(shí)還需要處理
 front_image_url = scrapy.Field(
 output_processor = MapCompose(return_value)
 )
 front_image_path = scrapy.Field()
 praise_nums = scrapy.Field(
 input_processor = MapCompose(get_nums)
 )
 comment_nums = scrapy.Field(
 input_processor = MapCompose(get_nums)
 )
 fav_nums = scrapy.Field(
 input_processor = MapCompose(get_nums)
 )
 # tags要做另行處理,因?yàn)閠ags我們需要的就是list
 tags = scrapy.Field(
 input_processor = MapCompose(remove_comment_tags),
 output_processor = Join(",")
 )
 content = scrapy.Field()

首先我們看到定義了一個(gè)類ArticleItemloader,在這個(gè)類中只有一句話,就是對(duì)于每個(gè)items都默認(rèn)采用list中的第一個(gè)元素,這樣我們就可以把每個(gè)items中的第一個(gè)元素取出來(lái)。但是要注意,有些items我們是必須要用list型的,比如我們給ImagePipeline的數(shù)據(jù)就要求必須是list型,這樣我們就需要對(duì)front_image_url單獨(dú)進(jìn)行處理。這里我們做了一個(gè)小技巧,對(duì)front_image_url什么都不錯(cuò),因?yàn)槲覀儌鬟^(guò)來(lái)的front_image_url就是list型
在items的Field中有兩個(gè)參數(shù),一個(gè)是input_processor,另一個(gè)是output_processor,這兩個(gè)參數(shù)可以幫助我們對(duì)items的list中的每個(gè)元素進(jìn)行處理,比如有些需要用md5進(jìn)行加密,有些需要用正則表達(dá)式進(jìn)行篩選或者排序等等。

在進(jìn)行mysql的pipeline之前,我們需要設(shè)計(jì)數(shù)據(jù)庫(kù),下面是我自己設(shè)計(jì)的數(shù)據(jù)庫(kù)的字段,僅供參考

這里我把url_object_id作為該表的主鍵,由于它不會(huì)重復(fù),所以適合做主鍵。

下面我們來(lái)看看數(shù)據(jù)庫(kù)的pipeline。

# -*- 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 codecs
import json
from twisted.enterprise import adbapi
import MySQLdb
import MySQLdb.cursors
 
 
class MysqlTwistedPipeline(object):
 """docstring for MysqlTwistedPipeline"""
 #采用異步的機(jī)制寫(xiě)入mysql
 def __init__(self, dbpool):
 self.dbpool = dbpool
 
 @classmethod
 def from_settings(cls, settings):
 dbparms = dict(
 host = settings["MYSQL_HOST"],
 db = settings["MYSQL_DBNAME"],
 user = settings["MYSQL_USER"],
 passwd = settings["MYSQL_PASSWORD"],
 charset='utf8',
 cursorclass=MySQLdb.cursors.DictCursor,
 use_unicode=True,
 )
 dbpool = adbapi.ConnectionPool("MySQLdb", **dbparms)
 
 return cls(dbpool)
 
 def process_item(self, item, spider):
 #使用twisted將mysql插入變成異步執(zhí)行
 query = self.dbpool.runInteraction(self.do_insert, item)
 query.addErrback(self.handle_error, item, spider) #處理異常
 return item
 
 def handle_error(self, failure, item, spider):
 # 處理異步插入的異常
 print (failure)
 
 def do_insert(self, cursor, item):
 #執(zhí)行具體的插入
 #根據(jù)不同的item 構(gòu)建不同的sql語(yǔ)句并插入到mysql中
 # insert_sql, params = item.get_insert_sql()
 # print (insert_sql, params)
 # cursor.execute(insert_sql, params)
 insert_sql = """
 insert into jobbole_article(title, url, create_date, fav_nums, url_object_id)
 VALUES (%s, %s, %s, %s, %s)
 """
 # 可以只使用execute,而不需要再使用commit函數(shù)
 cursor.execute(insert_sql, (item["title"], item["url"], item["create_date"], item["fav_nums"], item["url_object_id"]))

在這里我們只是演示一下,我們只向數(shù)據(jù)庫(kù)中插入5個(gè)字段的數(shù)據(jù),分別是title,url,create_date,fav_nums,url_object_id。

當(dāng)然你也可以再加入其它的字段。

首先我們看看from_settings這個(gè)函數(shù),它可以從settings.py文件中取出我們想想要的數(shù)據(jù),這里我們把數(shù)據(jù)庫(kù)的host,dbname,username和password都放在settings.py中。實(shí)際的插入語(yǔ)句還是在process_item中進(jìn)行,我們自己定義了一個(gè)函數(shù)do_insert,然后把它傳給dbpool中用于插入真正的數(shù)據(jù)。

最后我們來(lái)看看settings.py中的代碼,這里就很簡(jiǎn)單了。

MYSQL_HOST = "localhost"
MYSQL_DBNAME = "article_wilson"
MYSQL_USER = "root"
MYSQL_PASSWORD = "root"

其實(shí)這里是和pipeline中的代碼是想對(duì)應(yīng)的,別忘了把在settings.py中把pipeline打開(kāi)。

ITEM_PIPELINES = {
 # 'ArticleSpider.pipelines.ArticlespiderPipeline': 300,
 # 'ArticleSpider.pipelines.JsonWithEncodingPipeline': 1
 
 # # 'scrapy.pipelines.images.ImagePipeline': 1,
 # 'ArticleSpider.pipelines.JsonExporterPipleline': 1
 # 'ArticleSpider.pipelines.ArticleImagePipeline': 2
 # 'ArticleSpider.pipelines.MysqlPipeline': 1
 'ArticleSpider.pipelines.MysqlTwistedPipeline': 1
}

好了,現(xiàn)在我們可以跑一程序吧。

scrapy crawl jobbole

下面是運(yùn)行結(jié)果的截圖

好了,以上就是今天的全部?jī)?nèi)容了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用Python實(shí)現(xiàn)管理系統(tǒng)附源碼

    使用Python實(shí)現(xiàn)管理系統(tǒng)附源碼

    這篇文章主要為大家介紹了Python實(shí)現(xiàn)管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • python多線程超詳細(xì)詳解

    python多線程超詳細(xì)詳解

    這篇文章主要介紹了python多線程超詳細(xì)詳解,多線程這個(gè)知識(shí)點(diǎn)非常重要,想了解的同學(xué)可以參考下
    2021-04-04
  • Django中create和save方法的不同

    Django中create和save方法的不同

    這篇文章主要給大家介紹了關(guān)于Django中create和save方法的不同之處,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Django具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 解決Pytorch 訓(xùn)練與測(cè)試時(shí)爆顯存(out of memory)的問(wèn)題

    解決Pytorch 訓(xùn)練與測(cè)試時(shí)爆顯存(out of memory)的問(wèn)題

    今天小編就為大家分享一篇解決Pytorch 訓(xùn)練與測(cè)試時(shí)爆顯存(out of memory)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-08-08
  • Python 給下載文件顯示進(jìn)度條和下載時(shí)間的實(shí)現(xiàn)

    Python 給下載文件顯示進(jìn)度條和下載時(shí)間的實(shí)現(xiàn)

    這篇文章主要介紹了Python 給下載文件顯示進(jìn)度條和下載時(shí)間的代碼,本文通過(guò)實(shí)例代碼截圖相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Python中read()、readline()和readlines()三者間的區(qū)別和用法

    Python中read()、readline()和readlines()三者間的區(qū)別和用法

    這篇文章主要給大家介紹了關(guān)于Python中讀取文件的read()、readline()和readlines()方法三者間的區(qū)別和用法,需要的朋友可以參考下
    2017-07-07
  • 詳解Python虛擬機(jī)是如何實(shí)現(xiàn)閉包的

    詳解Python虛擬機(jī)是如何實(shí)現(xiàn)閉包的

    Python中的閉包是一個(gè)強(qiáng)大的概念,允許函數(shù)捕獲和訪問(wèn)其周?chē)淖饔糜?即使這些作用域在函數(shù)執(zhí)行完畢后也能被訪問(wèn),這篇文章將著重討論P(yáng)ython虛擬機(jī)是如何實(shí)現(xiàn)閉包的,文中有相關(guān)的代碼示例供大家參考,具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-12-12
  • Python常用數(shù)字處理基本操作匯總

    Python常用數(shù)字處理基本操作匯總

    這篇文章主要介紹了Python常用數(shù)字處理基本操作匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 在python plt圖表中文字大小調(diào)節(jié)的方法

    在python plt圖表中文字大小調(diào)節(jié)的方法

    今天小編就為大家分享一篇在python plt圖表中文字大小調(diào)節(jié)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • Python中__new__()方法適應(yīng)及注意事項(xiàng)詳解

    Python中__new__()方法適應(yīng)及注意事項(xiàng)詳解

    這篇文章主要介紹了Python中__new__()方法適應(yīng)及注意事項(xiàng)的相關(guān)資料,new()方法是Python中的一個(gè)特殊構(gòu)造方法,用于在創(chuàng)建對(duì)象之前調(diào)用,并負(fù)責(zé)返回類的新實(shí)例,它與init()方法不同,需要的朋友可以參考下
    2025-03-03

最新評(píng)論

巴塘县| 宜君县| 天门市| 金昌市| 通许县| 滦南县| 广安市| 平罗县| 曲麻莱县| 舒兰市| 洛阳市| 卫辉市| 大关县| 昭觉县| 佛冈县| 镇原县| 浦县| 忻州市| 香港 | 秭归县| 蓬莱市| 临安市| 宜黄县| 庆安县| 沙湾县| 大理市| 郯城县| 永丰县| 阿克苏市| 福清市| 定远县| 开阳县| 阜宁县| 屏东市| 富顺县| 女性| 乐安县| 洛川县| 嵊州市| 兴文县| 裕民县|