1,除錯scrapy
在作業中經常會用到除錯功能, 下面是一種scrapy提供的方法, 代碼如下:
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
...
if __main__ == "__main__":
process = CrawlerProcess(get_project_settings())
process.crawl('demo') # 你需要將此處的spider_name替換為你自己的爬蟲名稱
process.start()
2,讀取資料庫,獲取起始鏈接(或構造起始鏈接)
有時候, scrapy start_urls 需要從資料庫獲取
def start_requests(self):
db = pymysql.connect(host=settings.MYSQL_HOST,
user=settings.MYSQL_USER,
password=settings.MYSQL_PASSWORD,
database=settings.MYSQL_DATABASE,
port=settings.MYSQL_PORT
)
with db.cursor() as cursor:
cursor.execute('select url from url_table')
result = cursor.fetchall()
db.close()
for url in result:
# yield scrapy.Request(f"http://www.baidu.com/s?wd={url[0]}") # 自己通過資料庫回傳的欄位進行構造鏈接
yield scrapy.Request(url[0])
3,動態添加待爬url
同2, 將mysql部分去掉, 修改自己的就可以
4,常用設定, 自定義設定
有時候需要覆寫settings檔案中的設定, 就在spider檔案中寫custom_settings, 然后在里面配置一些資訊就可以了
class MySpider(scrapy.Spider):
...
custom_settings = {
'DEPTH_LIMIT': 5, # 爬取層速
'JOBDIR': '路徑' # 在指定路徑保存當前的進度,當中途退出爬蟲后,再次運行時可以從這個檔案中讀取之前的進度,繼續爬取.
'HTTPERROR_ALLOWED_CODES' : [302] # 302為暫時性的鏈接重置,當出現302時,應該繼續深入爬取內容,所以我們不忽略302的報錯,一般會設定為[301,302],301為永久性的鏈接重置.
'AUTOTHROTTLE_ENABLED' : True # 自動限速,可以參考網址: https://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/autothrottle.html
}
更多配置請參考主頁另一篇文章
5,常用pipeline
-
mysql pipeline
-
存在更新, 不存在插入
class MysqlUpdatePipeline: def __init__(self): self.database = settings.MYSQL_DATABASE self.port = settings.MYSQL_PORT self.password = settings.MYSQL_PASSWORD self.user = settings.MYSQL_USER self.host = settings.MYSQL_HOST self.cursor = None self.db = None def open_spider(self, spider): self.db = pymysql.connect(host=self.host, user=self.user, password=self.password, database=self.database, port=self.port ) self.cursor = self.db.cursor() def process_item(self, item, spider): data = https://www.cnblogs.com/ibry/p/dict(item) keys =', '.join(data.keys()) values = ', '.join(['% s'] * len(data)) update = ', '.join( [f'{tuple(item.keys())[i]} = % s' for i in range(len(data))]) sql = 'insert into % s (% s) values (% s) on duplicate key update % s' % ( item.table, keys, values, update) try: # 檢查連接是否斷開,如果斷開就進行重連 self.db.ping(reconnect=True) print('mysql超時重連') # 使用 execute() 執行sql self.cursor.execute(sql, tuple(data.values()) * 2) # 提交事務 self.db.commit() except Exception as e: print("操作出現錯誤:{}".format(e)) # 回滾所有更改 self.db.rollback() return item def close_spider(self, spider): self.db.close() -
直接插入, 操作跟更新差不多, 就將process_item中代碼覆寫或者修改即可
class MysqlPipeline: ... def process_item(self, item, spider): data = https://www.cnblogs.com/ibry/p/dict(item) keys =', '.join(data.keys()) values = ', '.join(['% s'] * len(data)) sql = 'insert into % s (% s) values (% s) on duplicate key update % s' % ( item.table, keys, values) try: # 檢查連接是否斷開,如果斷開就進行重連 self.db.ping(reconnect=True) self.cursor.execute(sql, data.values()) self.db.commit() except Exception as e: print("操作出現錯誤:{}".format(e)) self.db.rollback() return item
-
-
mongo pipeline
-
插入
class MongoPipeline: def __init__(self): self.client = pymongo.MongoClient(host=settings.MONGO_HOST, port=settings.MONGO_PORT) self.client.admin.authenticate(settings.MONGO_USER, settings.MONGO_PWD) self.db = self.client[settings.MONGO_DB] def process_item(self, item, spider): self.db[item.table].insert(dict(item)) # self.db[item.table].update_one({'id': item['id']}, {"$set": item}, upsert=True) return item def close_spider(self, spider): self.client.close() -
存在則更新, 不存在則插入, 其他代碼同上
class MongoPipeline: def process_item(self, item, spider): # 根據item中唯一id進行判斷, 實際運用中, 需要自己更改這個判斷欄位 self.db[item.table].update_one({'id': item['id']}, {"$set": item}, upsert=True) return item
-
-
scrapy redis 主從分布式-master_pipeline
-
class MasterRedisPipeline: def __init__(self): self.redis_table = settings.REDIS_KEY # 選擇表 self.redis_db = redis.Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=settings.REDIS_DB, password=settings.REDIS_PASSWORD) # redis資料庫連接資訊 def process_item(self, item, spider): # 存盤欄位自己可以根據自己需要單獨設定, 這里設定欄位名為url res = self.redis_db.lpush(self.redis_table, item['url']) return item def close_spider(self, spider): self.redis_db.close()
-
-
圖片下載中間件
-
需要繼承ImagesPipeline
-
需要在settings中指明存盤路徑, IMAGES_STORE = './images'
class ImagePipeline(ImagesPipeline): def file_path(self, request, response=None, info=None): url = request.url file_name = url.split('/')[-1] return file_name def item_completed(self, results, item, info): image_paths = [x['path'] for ok, x in results if ok] if not image_paths: raise DropItem('Image Downloaded Failed') return item def get_media_requests(self, item, info): # 根據自己需求設定url欄位 yield Request(item['url'])
-
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/118175.html
標籤:Python
