創建第一個scrapy工程-糗事百科
最近不少小伙伴兒,問我關於scrapy如何設置headers的問題,時間久了不怎么用,還真有的忘,全靠記憶去寫了,為了方便大家參考,也方便我以后的查閱,這篇文章就誕生了。本章內容從實戰出發讓我們熟悉如何用scrapy寫爬蟲,本篇內容主要是實戰,不講述過多的理論性東西,因為講多了我也不知道。😄

明確目標
首先,我們要明確我們的爬蟲最終的目的是什么,這里我們要做的是爬取糗事百科的熱門分類的前10頁信息。包括發布者和內容,因為入門教程所以我們寫的簡單點主要是熟悉這個過程,這個如何入手呢?
分析鏈接的變化
一般我們會通過點擊下一頁,然后觀察地址欄的信息來總結規律。
第一頁也就是首頁地址為:https://www.qiushibaike.com/
我們點擊下一頁可以發現第二頁的的連接為:https://www.qiushibaike.com/8hr/page/2/
第三頁:https://www.qiushibaike.com/8hr/page/3/
。。。以此類推第十頁的連接為:https://www.qiushibaike.com/8hr/page/10/
由此我們發現規律,從第二頁開始連接可以用https://www.qiushibaike.com/8hr/page/頁數/來表示,有時候我比較喜歡試探,怎么說呢,我們知道這個規律是從第二頁開始的,但是第一頁是沒有這個規律,但是我們不防試一試把第一頁的https://www.qiushibaike.com/改為https://www.qiushibaike.com/8hr/page/1/。然后我們訪問看看ok可以正常顯示。

於是我們就確定了鏈接,也就是頁數改為1-10就可以訪問相應的頁數了。
安裝scrapy
我們要確保正確安裝好了scrapy
針對mac和linux直接運行pip安裝即可。
pip install scrapy
但是windows的坑就比較多了,關於windows的安裝請參考我之前寫的這篇文章
:https://www.cnblogs.com/c-x-a/p/8996716.html。這里就不多說了。
創建scrapy工程
好了下面我們開始創建工程首先我們使用scrapy的第一個命令startproject,
使用方法:scrapy startproject xxx xxx就是你的項目名,這里我們給我們的項目起名qiushibaike。
scrapy startproject qiushibaike

然后我們會發現了多了一個文件名為qiushibaike的文件夾
然后我們通過命令創建一個事例工程
進入qiushibaike
cd qiushibaike
然后用下面scrapy的第二個命令genspider
使用方法 scrapy genspider spider_name domain
spider_name就是爬蟲的名字,每一個爬蟲有一個名字這個名字是唯一的,后面運行的時候也是通過這個名字來運行的,下面的qsbk就是我們的爬蟲名字,domain指定爬蟲的域也就是爬蟲的范圍。查找網頁我們發現域名為
scrapy genspider qsbk qiushibaike.com
看到以下命令證明我們成功的創建了項目。
Created spider 'qsbk' using template 'basic' in module:
qiushibaike.spiders.qsbk

開始編寫spider文件
我們這里使用pycharm把我們的爬蟲工程加載進來。
目錄結構如下

(注意:run.py是我后期自己添加的一個爬蟲入口文件)
修改settings.py文件
無視robots協議,將
ROBOTSTXT_OBEY = True
改為
ROBOTSTXT_OBEY = False

修改spider.py
我們先來看看我們訪問的網頁源碼對不對。
把qsbk.py 改為
# -*- coding: utf-8 -*-
import scrapy
class QsbkSpider(scrapy.Spider):
name = 'qsbk'
allowed_domains = ['qiushibaike.com']
start_urls = ['http://qiushibaike.com/']#種子url,列表類型表示支持多個
def parse(self, response):
print(response.text)#輸出源碼
創建入口文件運行
在項目的根目錄下創建一個run.py 來運行我們的工程
run.py的內容如下
# -*- coding: utf-8 -*-
# @Time : 2018/10/31 11:54 PM
# @Author : cxa
# @File : run.py.py
# @Software: PyCharm
from scrapy.cmdline import execute
execute(['scrapy','crawl','qsbk'])
運行以后我們發現一堆紅色的信息,這些都是scrapy 的日志內容,我們注意找是否有黑色字體的內容,一般print出來的內容是黑色字體和含有error的信息,以此了解我們的爬蟲哪個地方出錯了,

我們找到了error關鍵字,可以得知我們的爬蟲出錯了
2018-11-01 00:08:38 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.qiushibaike.com/> (failed 1 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
2018-11-01 00:08:38 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.qiushibaike.com/> (failed 2 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
2018-11-01 00:08:38 [scrapy.downloadermiddlewares.retry] DEBUG: Gave up retrying <GET https://www.qiushibaike.com/> (failed 3 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
2018-11-01 00:08:39 [scrapy.core.scraper] ERROR: Error downloading <GET https://www.qiushibaike.com/>
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/scrapy/core/downloader/middleware.py", line 43, in process_request
defer.returnValue((yield download_func(request=request,spider=spider)))
twisted.web._newclient.ResponseNeverReceived: [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed \
按照提示可以知道鏈接被關閉訪問失敗了,這種情況下我們就被反爬了,常見的應對措施是修改headers頭,下面我們就通過修改中間件來修改headers。
修改中間件加入headers信息
首先修改middlewares.py
class UserAgentMiddleware(object):
def __init__(self, user_agent_list):
self.user_agent = user_agent_list
@classmethod
def from_crawler(cls, crawler, *args, **kwargs):
# 獲取配置文件中的MY_USER_AGENT字段
middleware = cls(crawler.settings.get('MY_USER_AGENT'))
return middleware
def process_request(self, request, spider):
# 隨機選擇一個user-agent
request.headers['user-agent'] = random.choice(self.user_agent)
然后在settings啟用我們的中間件和設定MY_USER_AGENT的值:
MY_USER_AGENT = ["Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36",
"Mozilla/5.0+(Windows+NT+5.1)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/28.0.1500.95+Safari/537.36+SE+2.X+MetaSr+1.0",
"Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/50.0.2657.3+Safari/537.36"]
DOWNLOADER_MIDDLEWARES = {
'qiushibaike.middlewares.UserAgentMiddleware': 543,
}
然后我們再次運行,run.py文件。
再次運行
我們成功獲取了源碼,

。然后我們就需要進行解析內容了。
解析網頁中所需要的內容
因為這10頁的結構是類似的我們就拿第一頁為例:
在這里我們使用的解析方法為xpath,通過xpath可以解析出我們需要的內容,
打開谷歌瀏覽器的開發者工具,首先通過Elements模塊獲取當前頁所有內容的大概區域我們可以寫這樣的一個xpath。
"//div[@id='content-left']"
然后我們發現一頁25個內容,然后再去在每個內容里進行查找當前的標題和內容。
在qsbk.py文件的parse方法里加入這段內容
content_left_node=response.xpath("//div[@id='content-left']") #確定發布區的節點區域
div_node_list=content_left_node.xpath("./div")
for div_node in div_node_list:
title_node=div_node.xpath(".//div[@class='author clearfix']/a[contains(@onclick,'web-list-author-text')]/h2/text()")
content_node=div_node.xpath(".//div[@class='content']/span[1]")
content=content_node.xpath('string(.)')
print("發布者",title_node.extract_first().strip())
print("發布內容",content.extract_first().strip())
修改scrapy的日志顯示等級方便查看
前面運行過程中我們發現scrapy的日志信息非常的多,不容易找到我們想要的內容,這個時候我們可以通過修改settings.py文件通過修改log的等級,只顯示指定類型的log,打開settings.py我們加上下面的一句來設定log的等級為error
也就是只有錯誤的時候才顯示scrapy的log信息。
LOG_LEVEL = "ERROR"
然后再次運行,看到了我們我們需要的內容發布者和發布內容。
得到了這些我們現在只是打印了下,下面我們就來說如何存儲
保存結果到mongodb
mongodb是一個key-value型的數據庫,使用起來簡單,數據結構是鍵值對類型,在存儲過程中如果表不存在就會創建一個新的表。
下面我們開始來存儲我們的數據。
構造數據
因為我們需要接收一個鍵值對類型的數據,一般用dict,所以我們將代碼改成如下形式。qsbk.py文件新增內容:
item = {}
item['name'] = name
item['info'] = info
yield item
上面我們構造出了我們需要存儲的數據,然后通過yield傳遞到存儲部分,
下一步我們就要開始創建mongo連接的部分了。
創建mongo連接文件
把pipelines.py 文件改為
import pymongo
from scrapy.conf import settings
class MongoPipeline(object):
def __init__(self):
# 鏈接數據庫
self.client = pymongo.MongoClient(host=settings['MONGO_HOST'], port=settings['MONGO_PORT'])
if settings.get('MINGO_USER'):
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):
postItem = dict(item) # 把item轉化成字典形式
self.coll.insert(postItem) # 向數據庫插入一條記錄
return item
然后修改settings.py,首先添加mongo的幾個連接參數
MONGO_HOST = "127.0.0.1" # 主機IP
MONGO_PORT = 27017 # 端口號
MONGO_DB = "spider_data" # 庫名
MONGO_COLL = "qsbk" # collection名
然后打開pipe通道
ITEM_PIPELINES = {
'qiushibaike.pipelines.MongoPipeline': 300,
}
運行查看數據
我這里用的adminmongo,打開adminmogo連接數據庫,可以看到我們數據已經存在了。

結語
到此為止,我們一個簡單完整的scrapy小項目就完成了。 為了方便查看代碼已經上傳git:https://github.com/cxapython/qsbk.git
更多爬蟲學習以及python技巧,請關注公眾號:python學習開發。