9.5 58同城scrapy爬取代碼示例及存入Mongodb中

案例:爬取58同城

爬取58同城步驟如下:
- 在命令行輸入 scrapy startproject city58,使用cd city58進入項目目錄,使用scrapy genspider city58_test 58.com生成爬蟲

  • 訪問58同城網站,打開開發者工具,查看elements

  • 查找含有目標信息的元素,提取目標網頁的url,填入新建的Scrapy項目中Spider文件下的start_url中,並編寫Spider

  • 編寫Items(用於定義需要爬取的字段)和PIpeLine(處理Item)兩個文件,以及修改setting文件(啓動管道),創建main文件


運行main文件,啓動Scrapy爬蟲

文件結構如下圖:

代碼如下:

items.py:定義我們所要爬取的信息的相關屬性,此例中需要爬取的是name、price、url

import scrapy

class City58Item(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    price = scrapy.Field()
    url = scrapy.Field() 
city58_test.py:主要是用於定義請求鏈接,並使用pyquery選取目標元素
import scrapy
from pyquery import PyQuery
from ..items import City58Item
#點點一個是當前目錄一個是上級目錄

class City58TestSpider(scrapy.Spider):
    name = 'city58_test'  #必不可少的爬蟲名字,啓動的關鍵
    allowed_domains = ['58.com'] #主域名
    start_urls = ['http://bj.58.com/chuzu/']   #開始爬取的鏈接

    def parse(self, response):
        jpy = PyQuery(response.text)#生成選擇器對象
        li_list = jpy('body > div.mainbox > div.main > div.content > div.listBox > ul > li').items() #記得帶上.items()參數
        for it in li_list:
            a_tag = it(' div.des > h2 > a')
            item = City58Item()
            item['name'] = a_tag.text()   #a_tag取出文本
            item['url'] = a_tag.attr('href')  #取出href參數
            item['price'] = it('div.listliright > div.money > b').text()
            yield item   #把Item返回給引擎

            ##路徑選擇,可以直接右鍵元素-copy-copy select即可快速修改包裝路徑
pipeline.py:當item數據被city58_test爬蟲爬取好並返回給引擎以後,引擎會把item交給City58Pipeline這個管道處理。這個pipeline文件負責打開關閉文件,並寫入文件
import json

class City58Pipeline(object): #這個名字要和setting文件中的後半部分相同
    #打開文件
    def open_spider(self,spider):
        self.file = open('58_chuzu.txt', 'w' , encoding='utf8') #創建文件名,w寫入的方式
        print('打開文件了')
    #寫入文件
    def process_item(self, item, spider):
        line = '{}\n'.format(json.dumps(dict(item)))  #把item轉換成字符串,並且換行寫入不然是一坨了,並且注意是dict不是dic別寫錯
        #注意此處的寫法,不然最後生成的文件出錯
        self.file.write(line)
        return item #必須返回item
    #關閉文件
    def close_spider(self, spider):
        self.file.close()
        print('關閉文件了')
###### settings.py:開啓Ci

###以上問題總結:如何寫入文件:
如何把一個個對象寫入文件。涉及到序列化,即把對象變成一個文本。如何把dictionary寫入到文本中呢?經典方案是import jaon,把它變成一個json的字符串,然後存起來就ok了。
即:序列號函數json.dumps(),item其實就是一個dictionaty,但是離真正還是差一點。
於是json.dumps(dic(item)讓其變成真正的dic,並把其放入line變量中,即line=json.dumps(dic(item)。
--------------------------------------------------------------------------------
這其中有個問題,容易寫成一坨,就是你不斷地這麼寫只是在尾部追加,沒有換行符,
這時候我們要添加一個換行的機制,並把其format粘貼進來
ty58Pipeline這個管道,激活管道,setting文件
#取消註釋即可
ITEM_PIPELINES = { 
‘city58.pipelines.City58Pipeline’: 300, 
}
main.py:運行爬蟲,創建main.py文件

並且把執行命令寫進去,其中有個是文件名,然後debug運行即可。

from scrapy import cmdline
cmdline.execute("scrapy crawl city58_test".split())

若存在mongodb中 需要更改setting 文件和pipeline文件,其他文件保持不變,如下所示:

setting.py
ITEM_PIPELINES = {
   'city_58.pipelines.City58Pipeline': 300,
}

MONGO_HOST = '127.0.0.1'  # 主機IP
MONGO_PORT = 27017 #端口名
MONGO_DB = '58' #數據庫名
MONGO_COLL= 'hezu' #表名

pipline.py

import json
import pymongo
from scrapy.conf import settings

class City58Pipeline(object): #這個名字要和setting文件中的後半部分相同

    def __init__(self):
        #鏈接數據庫
        self.client = pymongo.MongoClient(host=settings['MONGO_HOST'], port=settings['MONGO_PORT'])
        # 數據庫登錄需要帳號密碼的話
        # self.client.admin.authenticate(settings['MINGO_USER'], settings['MONGO_PSW'])
        self.db = self.client[settings['MONGO_DB']]  # 獲得數據庫的句柄
        self.coll = self.db[settings['MONGO_COLL']]  # 獲得collection的句柄


    def process_item(self, item, spider):
        line = dict(item) #注意此處的寫法
        self.coll.insert(line)  # 向數據庫插入一條記錄
        return item

課後作業

試試看,通過自己查資料,能否搞明白以下代碼的作用:

import scrapy
import hashlib
from urllib.parse import quote

class ScreenshotPipeline(object):
    """Pipeline that uses Splash to render screenshot of
    every Scrapy item."""

    SPLASH_URL = "http://localhost:8050/render.png?url={}"

    def process_item(self, item, spider):
        encoded_item_url = quote(item["url"])
        screenshot_url = self.SPLASH_URL.format(encoded_item_url)
        request = scrapy.Request(screenshot_url)
        dfd = spider.crawler.engine.download(request, spider)
        dfd.addBoth(self.return_item, item)
        return dfd

    def return_item(self, response, item):
        if response.status != 200:
            # Error happened, return item.
            return item

        # Save screenshot to file, filename will be hash of url.
        url = item["url"]
        url_hash = hashlib.md5(url.encode("utf8")).hexdigest()
        filename = "{}.png".format(url_hash)
        with open(filename, "wb") as f:
            f.write(response.body)

        # Store filename in item.
        item["screenshot_filename"] = filename
        return item

補充資料

有能力的同學可以去GitHub瀏覽Scrapy的源碼,更深入地理解Scrapy的使用和操作方法
有興趣的同學可以嘗試去爬取京東的商品,這裏有一個京東爬蟲開源的項目,大家可以參考一下

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