糗事百科爬蟲首頁及全站段子爬取步驟詳解
手動反爬蟲:原博地址
知識梳理不易,請尊重勞動成果,文章僅發佈在CSDN網站上,在其他網站看到該博文均屬於未經作者授權的惡意爬取信息
如若轉載,請標明出處,謝謝!
1. 前提說明
前面的item內容字段數據的爬取採用了xpath語法和css語法,那麼這一部分就嘗試着使用re正則表達式來進行,關於基礎scrapy知識可以參看Scrapy安裝、詳細指令參數講解及第一個項目實例
2. 創建項目
在一個指定的文件路徑下,打開cmd,輸入創建爬蟲項目的指令,文件夾創建完成後,並進入提示路徑
scrapy startproject qsbk
→ 輸出的結果爲:(創建文件夾成功後,注意進入這個指定的文件夾下)
3. 創建爬蟲模板
這裏選擇的是basic模板,創建的指令如下
scrapy genspider -t basic jokes qiushibaike.com/text
→ 輸出的結果爲:(會在spiders文件夾下多出一個jokes.py文件)
4. items.py文件修改
根據要爬取的網站的內容,如下,可以確定要爬取的字段數據,共五個字段,分別爲:作者,鏈接,內容,點贊數,評論數(這些都可以在網頁源代碼中找到)
修改的item.py文件如下
5. 爬蟲模板文件修改
5.1 模板可行性檢驗
首先習慣性的創建一個爬蟲模板後,直接打印返回的內容,看看是否可以正常運行,修改最後一行代碼如下,然後在命令行執行爬取的指令
cmd執行的爬取指令
scrapy crawl jokes
輸出的結果中顯示如下(要求必須使用模擬瀏覽器的方式爬取)
進行代碼修改,設置瀏覽器請求頭,baisc模板創建後默認會生成爬取第一頁的網址,也就是start_urls
參數,這裏由於要使用請求頭訪問,因此可以把這個參數註釋掉,自己手動設置請求頭和起始網址,需要使用到start_requests
函數,注意導入Request
方法
保存後在cmd界面執行爬取命令,展示結果如下,可以發現能以正常獲取網頁內容
這一步的檢測非常重要,要養成一個習慣,在爬取內容之前,先測試這個模板是否是直接可用的,然後再進行爬取字段內容代碼的輸入
5.2 相關字段數據爬取
上面添加請求頭之後,就可以正常返回網頁請求的數據了,那麼接下來就是引入正則表達式,進行相關字段數據的爬取。由於是進行正則表達式提取,所以需要在網頁源代碼下進行匹配
1) 段子作者
首先需要導入items.py文件中的類名和re庫,通過上面的信息匹配可以看到作者信息都是在h2標籤中(兩個結果中選擇簡單有規律的標籤),對應的數據爬取的代碼如下
import scrapy
from scrapy.http import Request
from ..items import QsbkItem
import re
class JokesSpider(scrapy.Spider):
name = 'jokes'
allowed_domains = ['qiushibaike.com/text']
# start_urls = ['http://qiushibaike.com/text/']
def start_requests(self):
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'}
yield Request('http://qiushibaike.com/text/',headers=headers)
def parse(self, response):
item = QsbkItem()
txt = response.text
item['name'] = re.findall(r'<h2>\n(.*?)\n</h2>',txt)
print(item['name'],len(item['name']))
→ 輸出的結果爲:(剛好對應段子首頁的25個作者,後面的計數就是爲了驗證爬取數據的準確性)
2)段子鏈接
選取最近的網頁鏈接,進行信息提取,代碼如下,直接把網址部分替換
item['link'] = re.findall(r'a href="(.*?)" target="_blank" class="contentHerf"',txt)
print(item['link'],len(item['link']))
★★★ 3) 段子內容的匹配
可以看到內容都是在span標籤當中,因此可以嘗試進行獲取,代碼如下
item['content'] = re.findall(r'<span>\n\n\n(.*?)\n\n</span>',txt)
print(item['content'],len(item['content']))
→ 輸出的結果爲:(之前加上的計數,就是爲了驗證爬取數據的準確性,這裏明顯少了數據)
因此就需要進行問題的查找,內容都是在span標籤中,而span標籤太多了,不能作爲查找的關鍵詞(這裏的意思是如果只查找span這個單詞),因此可以查找上面的content標籤,對應的剛好爲25個結果,然後依次查看每個結果,最終發現問題,如下
a. 嘗試着第一次解決問題
第21處,發現多了一個省略號導致並不是兩個回車的格式
第25處,也是和上面一樣
因此代碼就需要進行修改,要求可以匹配到一個或者多個回車換行符,代碼如下,關於正則表達式的匹配模式可以參考正則表達式模式
#\s匹配字符,匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]
item['content'] = re.findall(r'<span>\s+(.*?)\s+</span>',txt)
print(item['content'],len(item['content']))
→ 輸出的結果爲:(這時候卻發現匹配的結果卻多了,存在不需要的信息)
b. 嘗試着第二次解決問題
再進行問題的查找,既然內容前後的回車換行符的問題解決了,那麼就只剩下內容裏面的回車換行符的問題了,因此代碼修改如下
#內容中也存在多行,所以偶多次換行的問題,這裏使用的就是*,匹配零次或者多次的換行符
item['content'] = re.findall(r'<span>\s+(.*?\s*.*?)\s+</span>',txt)
print(item['content'],len(item['content']))
→ 輸出的結果爲:(最後的計數檢驗證明爬取數據成功了)
4) 點贊數匹配
直接可以給出代碼
item['thumb_up'] = re.findall(r'<i class="number">(.*?)</i> 好笑',txt)
print(item['thumb_up'],len(item['thumb_up']))
5) 評論數匹配
也是可以直接給出代碼
item['comment'] = re.findall(r'<i class="number">(.*?)</i> 評論',txt)
print(item['comment'],len(item['comment']))
5.3 相關字段數據爬取全部代碼
也就是爬蟲模板jokes.py文件中的全部代碼,如下
# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
from ..items import QsbkItem
import re
class JokesSpider(scrapy.Spider):
name = 'jokes'
allowed_domains = ['qiushibaike.com/text']
# start_urls = ['http://qiushibaike.com/text/']
def start_requests(self):
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'}
yield Request('http://qiushibaike.com/text/',headers=headers)
def parse(self, response):
item = QsbkItem()
txt = response.text
item['name'] = re.findall(r'<h2>\n(.*?)\n</h2>',txt)
item['link'] = re.findall(r'a href="(.*?)" target="_blank" class="contentHerf"',txt)
item['content'] = re.findall(r'<span>\s+(.*?\s*.*?)\s+</span>',txt)
item['thumb_up'] = re.findall(r'<i class="number">(.*?)</i> 好笑',txt)
item['comment'] = re.findall(r'<i class="number">(.*?)</i> 評論',txt)
print(item['name'], len(item['name']))
print(item['link'],len(item['link']))
print(item['content'],len(item['content']))
print(item['thumb_up'],len(item['thumb_up']))
print(item['comment'],len(item['comment']))
return item
→ 輸出的結果爲:(5個字段的數據量均爲25,證明數據獲取成功)
6. settings.py文件修改
因爲要存儲爬取的數據,所以需要開啓pipeline管道,修改如下
7. pipeline.py文件修改
確保上一步進行操作了,不然的話,即使代碼修改好了也不會保存數據的。在保存數據之前,先查看一下返回的item數據是什麼樣子的,才能繼續下一步操作,很多時候數據的類型並不是我們以爲的那樣子,比如這裏的item就是,看上去像字典,實際上的輸出並不是。
操作如下,註釋掉模板文件的print語句,在pipeline.py文件中打印item數據及類型,代碼如下
class QsbkPipeline(object):
def process_item(self, item, spider):
print(item,type(item))
return item
在cmd執行爬蟲指令,輸出結果如下
經過查看,發現這種數據轉換成爲字典之後就是字典套列表的形式,可以直接轉化爲pandas中的DataFrame格式,然後生成csv或者xlsx文件,代碼修改如下
#先導入pandas庫
import pandas as pd
class QsbkPipeline(object):
def process_item(self, item, spider):
# print(type(item),item)
df = pd.DataFrame(dict(item)) #轉化爲字典後之間編程DataFrame數據
df.to_csv('jokes.csv',index=False,encoding='gbk') #注意編碼的格式
print('Finished!')
return item
→ 輸出的結果爲:(數據自動按照設置的字段的先後進行輸出了,如過是要在自定義字段輸出,因爲是DataFrame數據,就變得超級簡單了,通過重新制定列順序即可)
至此,結合正則表達式爬取糗事百科段子首頁步驟詳解就梳理完畢,下一個博客更新:自動化模板爬取糗事百科全站段子內容步驟詳解