scrapy項(xiàng)目模板地址:https://github.com/w-x-x-w/Spider-Project
Scrapy簡介
Scrapy是什么?
- Scrapy是一個(gè)健壯的爬蟲框架,可以從網(wǎng)站中提取需要的數(shù)據(jù)。是一個(gè)快速、簡單、并且可擴(kuò)展的方法。Scrapy使用了異步網(wǎng)絡(luò)框架來處理網(wǎng)絡(luò)通訊,可以獲得較快的下載速度,因此,我們不需要去自己實(shí)現(xiàn)異步框架。并且,Scrapy包含了各種中間件接口,可以靈活的完成各種需求。所以我們只需要定制開發(fā)幾個(gè)模塊就可以輕松的實(shí)現(xiàn)一個(gè)爬蟲,用來抓取網(wǎng)頁上的各種內(nèi)容。
- Scrapy并不是一個(gè)爬蟲,它只是一個(gè)“解決方案”,也就是說,如果它訪問到一個(gè)“一無所知”的網(wǎng)站,是什么也做不了的。Scrapy是用于提取結(jié)構(gòu)化信息的工具,即需要人工的介入來配置合適的XPath或者CSS表達(dá)式。Scrapy也不是數(shù)據(jù)庫,它并不會儲存數(shù)據(jù),也不會索引數(shù)據(jù),它只能從一堆網(wǎng)頁中抽取數(shù)據(jù),但是我們卻可以將抽取的數(shù)據(jù)插入到數(shù)據(jù)庫中。
Scrapy架構(gòu)
Scrapy Engine (引擎): 是框架的核心,負(fù)責(zé)Spider、ItemPipeline、Downloader、Scheduler中間的通訊,信號、數(shù)據(jù)傳遞等。并在發(fā)生相應(yīng)的動作時(shí)觸發(fā)事件。
**Scheduler (調(diào)度器): **它負(fù)責(zé)接受引擎發(fā)送過來的Request請求,并按照一定的方式進(jìn)行整理排列,入隊(duì),當(dāng)引擎需要時(shí),提供給引擎。
**Downloader (下載器):**負(fù)責(zé)下載引擎發(fā)送的所有Requests請求,并將其獲取到的Responses交還給引擎。
**Spider (爬蟲):**負(fù)責(zé)處理由下載器返回的Responses,并且從中分析提取數(shù)據(jù),獲取Item字段需要的數(shù)據(jù),并將需要跟進(jìn)的URL提交給Scrapy Engine,并且再次進(jìn)入Scheduler。
**Item Pipeline (項(xiàng)目管道):**它負(fù)責(zé)處理Spider中獲取到的Item,并進(jìn)行進(jìn)行后期處理(清理、驗(yàn)證、持久化存儲)的地方.
**Downloader Middlewares (下載中間件):**引擎與下載器間的特定鉤子,一個(gè)可以自定義擴(kuò)展下載功能的組件。處理下載器傳遞給引擎的Response。
**Spider Middlewares(爬蟲中間件):**引擎和Spider間的特定鉤子,(處理進(jìn)入Spider的Responses,和從Spider出去的Requests)
快速開始-項(xiàng)目實(shí)戰(zhàn)
我們這里以某新聞網(wǎng)站新聞推送為例編寫項(xiàng)目,僅用于學(xué)習(xí),請勿惡意使用
安裝 Scrapy
pip install Scrapy
創(chuàng)建項(xiàng)目
scrapy startproject 項(xiàng)目名
HuxiuSpider/
scrapy.cfg
HuxiuSpider/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
...
這些文件分別是:
-
scrapy.cfg
: 項(xiàng)目的配置文件 -
HuxiuSpider/
: 該項(xiàng)目的python模塊。之后您將在此加入代碼。 -
HuxiuSpider/items.py
: 項(xiàng)目中的item文件. -
HuxiuSpider/pipelines.py
: 項(xiàng)目中的pipelines文件. -
HuxiuSpider/settings.py
: 項(xiàng)目的設(shè)置文件. -
HuxiuSpider/spiders/
: 放置spider代碼的目錄.
更改設(shè)置
- 注釋robotstxt_obey
# 第21行
# Obey robots.txt rules
# ROBOTSTXT_OBEY = True
- 設(shè)置User-Agent
# 第18行
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = "HuxiuSpider (+http://www.yourdomain.com)"
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
- 設(shè)置訪問延遲
# 第29行
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 3
開啟pipline
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
"HuxiuSpider.pipelines.HuxiuspiderPipeline": 300,
}
開啟cookie(無需操作)(可選操作)
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
設(shè)置頻率(可不操作)
# The download delay setting will honor only one of:
# 定義了每個(gè)域名同時(shí)發(fā)送的請求數(shù)量
CONCURRENT_REQUESTS_PER_DOMAIN = 2
# 定義了每個(gè)IP同時(shí)發(fā)送的請求數(shù)量
#CONCURRENT_REQUESTS_PER_IP = 16
命令行快速生成模板:
scrapy genspider huxiu_article api-article.huxiu.com
Spider是用戶編寫用于從單個(gè)網(wǎng)站(或者一些網(wǎng)站)爬取數(shù)據(jù)的類。
其包含了一個(gè)用于下載的初始URL,如何跟進(jìn)網(wǎng)頁中的鏈接以及如何分析頁面中的內(nèi)容, 提取生成 item
的方法。
為了創(chuàng)建一個(gè)Spider,您必須繼承 scrapy.Spider
類, 且定義以下三個(gè)屬性:
-
name
: 用于區(qū)別Spider。 該名字必須是唯一的,您不可以為不同的Spider設(shè)定相同的名字。 -
start_urls
: 包含了Spider在啟動時(shí)進(jìn)行爬取的url列表。 因此,第一個(gè)被獲取到的頁面將是其中之一。 后續(xù)的URL則從初始的URL獲取到的數(shù)據(jù)中提取。(也可以刪除此變量,但要重寫start_requests
方法) -
parse()
是spider的一個(gè)方法。 被調(diào)用時(shí),每個(gè)初始URL完成下載后生成的Response
對象將會作為唯一的參數(shù)傳遞給該函數(shù)。 該方法負(fù)責(zé)解析返回的數(shù)據(jù)(response data),提取數(shù)據(jù)(生成item
)以及生成需要進(jìn)一步處理的URL的Request
對象。
以下為我們的第一個(gè)Spider代碼,保存在 HuxiuSpider/spiders
目錄下的 huxiu_article.py
文件中:
我們對于此段代碼進(jìn)行必要的解釋:
向一個(gè)url發(fā)送post請求,發(fā)送一個(gè)時(shí)間戳,可以獲取這個(gè)時(shí)間戳以后的新聞推送,然后就是推送數(shù)據(jù),關(guān)于數(shù)據(jù)提取等操作可以點(diǎn)開鏈接頁自行觀察,太過簡單。
爬蟲程序模板:
新聞列表頁爬蟲
import json
import time
import scrapy
from HuxiuSpider.items import HuxiuspiderItem
class HuxiuArticleSpider(scrapy.Spider):
def __init__(self):
# 'https://www.huxiu.com/article/'
self.url = 'https://api-article.huxiu.com/web/article/articleList'
name = "huxiu_article"
allowed_domains = ["api-article.huxiu.com"]
def start_requests(self):
timestamp = str(int(time.time()))
form_data = {
"platform": "www",
"recommend_time": timestamp,
"pagesize": "22"
}
yield scrapy.FormRequest(url=self.url, formdata=form_data, callback=self.parse)
def parse(self, response):
item = HuxiuspiderItem()
res = response.json()
success = res['success']
print(res)
if success:
data = res['data']
is_have_next_page = data['is_have_next_page']
last_dateline = data['last_dateline']
total_page = data['total_page']
dataList = data['dataList']
for data_obj in dataList:
item['url'] = 'https://www.huxiu.com/article/' + data_obj['aid'] + '.html'
item['title'] = data_obj['title']
item['author'] = data_obj['user_info']['username']
item['allinfo'] = json.dumps(data_obj, ensure_ascii=False)
item['visited'] = False
yield item
if is_have_next_page:
form_data = {
"platform": "www",
"recommend_time": str(last_dateline),
"pagesize": "22"
}
yield scrapy.FormRequest(url=self.url, formdata=form_data, callback=self.parse)
else:
raise Exception('請求新聞列表的時(shí)候失敗了~')
Item模板:
Item
是保存爬取到的數(shù)據(jù)的容器;其使用方法和python
字典類似, 并且提供了額外保護(hù)機(jī)制來避免拼寫錯(cuò)誤導(dǎo)致的未定義字段錯(cuò)誤。
類似在ORM中做的一樣,您可以通過創(chuàng)建一個(gè) scrapy.Item
類, 并且定義類型為 scrapy.Field
的類屬性來定義一個(gè)Item。 (如果不了解ORM, 不用擔(dān)心,您會發(fā)現(xiàn)這個(gè)步驟非常簡單)(ORM其實(shí)就是使用類的方式與數(shù)據(jù)庫進(jìn)行交互)
首先根據(jù)需要從huxiu.com
獲取到的數(shù)據(jù)對item
進(jìn)行建模。 我們需要從dmoz
中獲取名字,url
,以及網(wǎng)站的描述。 對此,在item
中定義相應(yīng)的字段。編輯 HuxiuSpider
目錄中的 items.py
文件:
import scrapy
class HuxiuspiderItem(scrapy.Item):
url = scrapy.Field()
title = scrapy.Field()
author = scrapy.Field()
# 存儲盡量多的信息是必要的,以應(yīng)對需求變更
allinfo=scrapy.Field()
visited=scrapy.Field()
一開始這看起來可能有點(diǎn)復(fù)雜,但是通過定義item, 您可以很方便的使用Scrapy的其他方法。而這些方法需要知道您的item的定義。
piplines模板:
from pymongo import MongoClient
from pymongo.errors import DuplicateKeyError
class HuxiuspiderPipeline:
def __init__(self):
self.client=MongoClient('localhost',
username='spiderdb',
password='password',
authSource='spiderdb',
authMechanism='SCRAM-SHA-1')
self.db = self.client['spiderdb']
self.collection = self.db['huxiu_links']
self.collection.create_index("url", unique=True)
def process_item(self, item, spider):
item = dict(item)
try:
self.collection.insert_one(item)
except DuplicateKeyError as e:
pass
return item
def close_spider(self, spider):
self.client.close()
運(yùn)行爬蟲
進(jìn)入項(xiàng)目的根目錄,執(zhí)行下列命令啟動spider
:
scrapy crawl huxiu_article
# scrapy crawl huxiu_article -o dmoz.csv
完善項(xiàng)目-多層爬取
yield scrapy.Request(item['url'], meta={'item': item}, callback=self.detail_parse)
https://blog.csdn.net/ygc123189/article/details/79160146
注意事項(xiàng)
自定義spider起始方式
也可以是查詢數(shù)據(jù)庫的結(jié)果,但要注意數(shù)據(jù)統(tǒng)一性,因?yàn)閟crapy是異步爬取
自定義item類型與有無
spider爬取的結(jié)果封裝到item對象中,再提交給pipeline持久化,那么當(dāng)然也可以忽略item對象,傳遞你想要的數(shù)據(jù)格式直接到pipeline。文章來源:http://www.zghlxwxcb.cn/news/detail-708961.html
item與pipeline對應(yīng)關(guān)系
item的意思是數(shù)據(jù)實(shí)例,一個(gè)item提交后,會經(jīng)過所有的pipeline,pipeline的意思是管道,就是對數(shù)據(jù)的一系列操作,設(shè)置中的管道優(yōu)先級就是管道處理數(shù)據(jù)的順序,比如日志操作等。
如果要讓某一個(gè)pipeline只處理某些類型的item,可以在item進(jìn)入pipelne的時(shí)候判斷一下是否是你想要處理的item類型。示例如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-708961.html
class doubanPipeline(object):
def process_item(self, item, spider):
#判斷item是否為Item1類型
if isinstance(item,doubanTextItem):
# 操作item
return item
scrapy是異步執(zhí)行的
同時(shí)運(yùn)行多個(gè)爬蟲
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
settings = get_project_settings()
crawler = CrawlerProcess(settings)
crawler.crawl('exercise')
crawler.crawl('ua')
crawler.start()
crawler.start()
post表單數(shù)據(jù)傳輸需要是字符串
自定義請求頭
import scrapy
class AddHeadersSpider(scrapy.Spider):
name = 'add_headers'
allowed_domains = ['sina.com']
start_urls = ['https://www.sina.com.cn']
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate",
'Content-Length': '0',
"Connection": "keep-alive"
}
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url, headers=self.headers, callback=self.parse)
def parse(self,response):
print("---------------------------------------------------------")
print("response headers: %s" % response.headers)
print("request headers: %s" % response.request.headers)
print("---------------------------------------------------------")
scrapy的FormRequest發(fā)送的是表單數(shù)據(jù)類型,如果要發(fā)送json類型需要使用Request
ts = round(time.time() * 1000)
form_data = {
"nodeId": id_str,
"excludeContIds": [],
"pageSize": '20',
"startTime": str(ts),
"pageNum": '1'
}
yield scrapy.Request(url=self.url,method='POST',headers=self.headers,
body=json.dumps(form_data), callback=self.parse,
meta={'id_str': id_str})
到了這里,關(guān)于Scrapy簡介-快速開始-項(xiàng)目實(shí)戰(zhàn)-注意事項(xiàng)-踩坑之路的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!