爬蟲開發步驟
一、環境介紹
開發工具:pycharm(社區版本)
python版本:3.7.4
scrapy版本:1.7.3
二、整體步驟
1.創建項目:scrapy startproject xxx(項目名字,不區分大小寫)
2.明確目標 (編寫items.py):明確你想要抓取的目標
3.製作爬蟲 (spiders/xxspider.py):製作爬蟲開始爬取網頁
4.存儲內容 (pipelines.py):設計管道存儲爬取內容
5.設置settings.py:
- USER_AGENT=網頁中-F12-網絡-找到爬取地址的請求-右側看消息頭-找到USER_AGENT填寫到該處;
- ROBOTSTXT_OBEY=False忽略被爬取網站的允許爬取列表限制,Ture根據授權列表爬取,沒有權限的不去爬取
- DOWNLOAD_DELAY=下載延遲,數值
- ITEM_PIPELINES=多個管道處理時設置優先級,根據:xx冒號後面的數值大小排序
6.啓動程序的py文件(start.py):等同於此命令(scrapy crawl xxx -o xxx.json)
三、開發準備
1.在pycharm工具setting中安裝scrapy插件
2.項目右鍵選擇打開終端
3.在終端中輸入爬蟲創建命令
執行成功後在項目目錄下生成爬蟲項目
項目結構如下
3.各個文件功能介紹
(1)iterms.py是用於封裝爬蟲爬取內容的實體,具體如下:
import scrapy
class PachongItem(scrapy.Item):
# define the fields for your item here like:
date = scrapy.Field()
open = scrapy.Field()
close = scrapy.Field()
height = scrapy.Field()
low = scrapy.Field()
updownd = scrapy.Field()
turnrate = scrapy.Field()
count = scrapy.Field()
如果要集成django,使用django的持久化對象以及其數據庫操作能力的話,需要安裝scrapy_djangoitem插件,然後做如下引用
import scrapy
from scrapy_djangoitem import DjangoItem
import blog.models as m # 保證django項目與爬蟲項目在一個工程下,然後引用django的實體模型
class PachongItem(DjangoItem): # scrapy.Item
# define the fields for your item here like:
# date = scrapy.Field()
# open = scrapy.Field()
# close = scrapy.Field()
# height = scrapy.Field()
# low = scrapy.Field()
# updownd = scrapy.Field()
# turnrate = scrapy.Field()
# count = scrapy.Field()
django_model = m.Spider # m.spider是django中定義的實體
(2)pachong_spider.py爬蟲主體方法,文件名可以自定義
from datetime import datetime
from decimal import Decimal
import scrapy
import pachong.items as items
# from items import PachongItem
# 命令行創建爬蟲項目命令:scrapy startproject 項目名稱
class PobotSpider(scrapy.Spider):
# 爬蟲的名稱,也就是該文件名稱,不能亂寫,寫其他的會報錯:找不到爬蟲文件
name = 'pachong_spider'
# 爬蟲允許抓取的域名
allowed_domains = ['quotes.money.163.com']
# 爬蟲抓取數據地址,給調度器
start_urls = ['http://quotes.money.163.com/trade/lsjysj_600051.html?year=2018&season=1']
# *args(多個參數無key值,字符串列表), **kwargs(多個參數有key值,字典列表)
def __init__(self, *args, **kwargs):
super(PobotSpider, self).__init__(*args, **kwargs)
url = 'http://quotes.money.163.com/trade/lsjysj_600051.html?year='+kwargs['year']+'&season='+kwargs['jd']
self.start_urls = [url]
print(self.start_urls)
def parse(self, response):
# # 打印返回結果
# print(response.text)
# xpath語法:根據抓取網頁的目錄結構, 等到上面結果, 意思是選取class爲article的div下, class爲grid_view的ol下的所有li標籤
# extract() 獲取真實內容;extract_first()獲取第一個匹配的真是內容;//全局匹配包含子節點孫子節點,全級別搜索;"/"根節
# 點匹配子節點不包含孫子節點,檢索一級標籤;屬性匹配div[@id="name"];text()匹配標籤內的文本;.get()/.getall()獲取第一個匹配的文本/全部匹配的文本
# response.xpath(’//div[@class=“col1”]/div’)[0].xpath(’./a/div/span/text()’).getall();./或.//當前選擇的標籤內容中搜索
# ;../或..//父級標籤內搜索子或孫子標籤;
# response.xpath(’//div[@class=“col1”]/div’)[0].xpath(’./a/div/span/@class’).getall()獲取選擇標籤的class屬性值
# 支持切片
stock_list = response.xpath("//div[@class='area']//div[@class='inner_box']//table//tr")
for index, i_item in enumerate(stock_list):
if index == 0:
continue
stock_item = items.PachongItem()
# 1.DoubanItem() 模型初始化
# 2.douban_item['serial_number'] 設置模型變量serial_number值,
# 3.i_item.xpath(".//div[@class='item']//em/text()") 對返回結果進一步篩選, 並且以"." 開頭表示拼接, 以text()結束表示獲取其信息
# 4.extract_first() xpath匹配器返回的是一個list,即使只有一個值也是放在list中的,因此要想直接獲取字符串,需要獲取結果的第一個值
# 也就是用extract_fist(),也可以用索引xpath()[0]
stock_item['date'] = datetime.strptime(i_item.xpath(".//td[1]/text()").extract_first(), '%Y-%m-%d')
stock_item['open'] = Decimal(i_item.xpath(".//td[2]/text()").extract_first())
stock_item['height'] = Decimal(i_item.xpath(".//td[3]/text()").extract_first())
stock_item['low'] = Decimal(i_item.xpath(".//td[4]/text()").extract_first())
stock_item['close'] = Decimal(i_item.xpath(".//td[5]/text()").extract_first())
stock_item['updownd'] = Decimal(i_item.xpath(".//td[7]/text()").extract_first())
stock_item['count'] = Decimal(i_item.xpath(".//td[10]/text()").extract_first())
stock_item['turnrate'] = Decimal(i_item.xpath(".//td[11]/text()").extract_first())
# yield 就是一個集合對象,可以將多次返回的值存入到一個集合迭代器中。
yield stock_item
(3)pipelines.py用於持久化爬取的數據,並進行清洗過濾,可以有多個pipeline
不集成django的寫法如下:
import pymysql
# pipeline管道,用於持久化爬取的數據,並進行清洗過濾,可以有多個pipeline
# 繼承object類,重寫了幾個方法
# 可以多個pipeline 實現類,通過settings.py中的ITEM_PIPELINES配置格式:‘類路徑’:級別(整型數值),與優先級係數來判定哪個先執行
# 帶@classmethod的是類方法,類方法不實例化,可以理解爲全局方法,重寫時也需要帶此註解
class PachongPipeline(object):
movieInsert = '''insert into blog_spider(date,open,close,height,low,updownd,turnrate,count)
values('{date}','{open}','{close}','{height}','{low}',
'{updownd}','{turnrate}','{count}')'''
def __init__(self):
self.conn = pymysql.connect(user='root', password='@bjive321',
host='59.110.138.8', port=3306,
database='blog', use_unicode=True,
charset='utf8')
self.cursor = self.conn.cursor()
self.conn.autocommit(True)
def process_item(self, item, spider):
# pymysql.escape_string用於轉譯,將字符串內的轉義字符,轉譯
sql_text = self.movieInsert.format(
date=datetime.datetime.strptime(pymysql.escape_string(item['date']), '%Y-%m-%d'),
open=Decimal(pymysql.escape_string(item['open'])),
close=Decimal(pymysql.escape_string(item['close'])),
height=Decimal(pymysql.escape_string(item['height'])),
low=Decimal(pymysql.escape_string(item['low'])),
updownd=Decimal(pymysql.escape_string(item['updownd'])),
turnrate=Decimal(pymysql.escape_string(item['turnrate'])),
count=Decimal(pymysql.escape_string(item['count'])))
self.cursor.execute(sql_text)
def close_spider(self, spider):
self.cursor.close()
self.conn.close()
集成django寫法如下:
import pymysql
# pipeline管道,用於持久化爬取的數據,並進行清洗過濾,可以有多個pipeline
# 繼承object類,重寫了幾個方法
# 可以多個pipeline 實現類,通過settings.py中的ITEM_PIPELINES配置格式:‘類路徑’:級別(整型數值),與優先級係數來判定哪個先執行
# 帶@classmethod的是類方法,類方法不實例化,可以理解爲全局方法,重寫時也需要帶此註解
class PachongPipeline(object):
# movieInsert = '''insert into blog_spider(date,open,close,height,low,updownd,turnrate,count)
# values('{date}','{open}','{close}','{height}','{low}',
# '{updownd}','{turnrate}','{count}')'''
def __init__(self):
self.conn = pymysql.connect(user='root', password='@bjive321',
host='59.110.138.8', port=3306,
database='blog', use_unicode=True,
charset='utf8')
self.cursor = self.conn.cursor()
self.conn.autocommit(True)
def process_item(self, item, spider):
# # pymysql.escape_string用於轉譯,將字符串內的轉義字符,轉譯
# sql_text = self.movieInsert.format(
# date=datetime.datetime.strptime(pymysql.escape_string(item['date']), '%Y-%m-%d'),
# open=Decimal(pymysql.escape_string(item['open'])),
# close=Decimal(pymysql.escape_string(item['close'])),
# height=Decimal(pymysql.escape_string(item['height'])),
# low=Decimal(pymysql.escape_string(item['low'])),
# updownd=Decimal(pymysql.escape_string(item['updownd'])),
# turnrate=Decimal(pymysql.escape_string(item['turnrate'])),
# count=Decimal(pymysql.escape_string(item['count'])))
# self.cursor.execute(sql_text)
item.save()
def close_spider(self, spider):
self.cursor.close()
self.conn.close()
(4)settings.py用於爬蟲配置信息的設置
如果集成django配置如下:
import os
import sys
import django
#======集成django需要增加以下內容,不集成則不需要===start======
sys.path.append(r"E:\pycharm\pystudy\blogs") # django項目的絕對路徑
os.environ['DJANGO_SETTINGS_MODULE'] = 'blogs.settings' # Django工程名.settings
# 手動初始化Django:
django.setup()
#=====end=================================
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36'
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 0.5
#可以配置多個管道
ITEM_PIPELINES = {
'pachong.pipelines.PachongPipeline': 300,
}
(5)創建一個main.py用於啓動爬蟲
cmdline.execute('scrapy crawl pachong_spider'.split())
4.啓動爬蟲
ok
5.遇到的問題解決
引入包的時候可能會找不到路徑,在工具,File->Settings->python console選中右側紅框內容
然後右鍵項目中引用涉及到的目錄文件夾,選擇如下:
即可。
四、django啓動爬蟲
如果需要在django頁面啓動爬蟲的話需要安裝scrapyd,安裝方法請自定網查
安裝好後執行scrapyd啓動服務,默認端口是6800
在django頁面增加一個按鈕,執行start請求,對應url與view中加入相關配置
啓動方法代碼如下:
#在線啓動爬蟲
def start_scrapy(request):
# 獲取頁面傳參,要區分請求類型是POST還是GET,不同請求用不同的方法接收參數
year = request.POST.get('year')
jd = request.POST.get('jd')
url = 'http://127.0.0.1:6800/schedule.json'
# spider是執行scrapy list返回的名稱,參數問題:除了內置key的參數外如project,spider等,其他參數均由爬蟲初始化函數的kwargs接收
# 同時jobid也有kwargs接收,**kwargs是接收字典型的參數,帶有key值的
data = {'project': 'pachong', 'spider': 'pachong_spider', 'year': year, 'jd': jd}
print(requests.post(url=url, data=data))
return JsonResponse({'result': 'ok'})