1. 程式人生 > 其它 >C++中全排列函式next_permutation(2)

C++中全排列函式next_permutation(2)

爬蟲基本流程

1.指定url

url = "https://www.aqistudy.cn/historydata/"

2.UA偽裝、防盜鏈

模擬瀏覽器

 headers = {
        'user-agent': 'Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36'  # UA 偽裝
     "Referer": "....."   # 防盜鏈
    }

3.請求引數的處理

data = {
    "page":"",
    "query": ""
}

4.發起請求

response = requests.post(url=url, data=data, headers=headers)

# 模擬登入傳送請求
session = reuqests.Session()
session.post(headers=headers,url=url)

5.獲取響應資料

# 網頁原始碼
data =response.text

#圖片資料  二進位制資料
data =response.content

#json資料
data =response.json()

6.持久化儲存

with open("filename","w",enconding="utf-8") as f:
    f.write(data)  
    # 將資料寫到filename 檔案中
    
# 二進位制檔案
with open("filename","wb") as f:
    f.write(data)
    # 將二進位制資料data寫入filename中

中文亂碼解決

1.檢視原始碼格式:

​ 開啟開發者工具 2、在console 中輸入“document.charset”檢視頁面編碼

2.解決:

​ 如果編碼格式是utf-8:

response = requests.get(url=url, headers=headers)
response.encoding = "utf-8"  # 最重要
tree = etree.HTML(response.text)

​ 如果編碼格式是GBK:

response = requests.get(url=url, headers=headers)
response.encoding = "GBK"
tree = etree.HTML(response.text)

bs4

資料解析的原理

1.例項化一個BeautifulSoup物件,並且將頁面原始碼資料載入到該物件中
2.通過呼叫BeautifulSoup物件中相關的屬性或者方法進行標籤定位和資料提取

環境安裝

pip install bs4
pip install lxml

資料解析的方法和屬性

標籤定位

soup.tagName # 返回的是文件中第一次出現的tagName對應的標籤

soup.find():

find('tagName') # 等同於soup.div

屬性定位:

soup.find('div',class_/id/attr='song')

soup.find_all('tagName'):返回符合要求的所有標籤(列表)

select:

select('某種選擇器(id,class,標籤...選擇器)'),返回的是一個列表。

層級選擇器:

soup.select('.tang > ul > li > a') # >表示的是一個層級

oup.select('.tang > ul a') # 空格表示的多個層級

獲取標籤之間的文字資料:

soup.a.text/string/get_text()

text/get_text() # 可以獲取某一個標籤中所有的文字內容

string:# 只可以獲取該標籤下面直系的文字內容

獲取標籤中屬性值:

soup.a['href']

使用

例項化BeautifulSoup物件

  1. 將本地的html文件中的資料載入到該物件中

    fp = open('./test.html','r',encoding='utf-8')
    soup = BeautifulSoup(fp,'lxml')
    
  2. 將網際網路上獲取的頁面原始碼載入到該物件中

    page_text = response.text
    soup = BeatifulSoup(page_text,'lxml')
    

案列

import requests
from bs4 import BeautifulSoup

if __name__ == "__main__":
    url = "http://www.shicimingju.com/book/sanguoyanyi.html"
    headers = {
        'user - agent': 'Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36'
    }
    data = requests.get(url=url, headers=headers)
    data.encoding = "utf-8"
    soup = BeautifulSoup(data.text, "lxml")
    all_title = soup.select(".book-mulu>ul a")
    for title in all_title:
        url2 = "https://www.shicimingju.com" + title["href"]
        res = requests.get(url=url2, headers=headers)
        res.encoding = "utf-8"
        soup = BeautifulSoup(res.text, "lxml")
        title = title.text.split("·")[1]
        with open(f"三國/{title}", "w", encoding="utf-8") as f:
            f.write(soup.select(".chapter_content")[0].text)

xpath

解析原理

​ 1.例項化一個etree的物件,且需要將被解析的頁面原始碼資料載入到該物件中。
​ 2.呼叫etree物件中的xpath方法結合著xpath表示式實現標籤的定位和內容的捕獲。

環境的安裝

​ - pip install lxml

例項化一個etree物件

	from lxml import etree

​ 1.將本地的html文件中的原始碼資料載入到etree物件中:
​ etree.parse(filePath)
​ 2.可以將從網際網路上獲取的原始碼資料載入到該物件中
​ etree.HTML('page_text')

xpath表示式

/:表示的是從根節點開始定位。表示的是一個層級。

//:表示的是多個層級。可以表示從任意位置開始定位。

# 屬性定位
//div[@class='song'] /tag[@attrName="attrValue"]

# 索引定位
//div[@class="song"]/p[3] 索引是從1開始的。

# 取文字
    /text() 獲取的是標籤中直系的文字內容
    //text() 標籤中非直系的文字內容(所有的文字內容)
    
# 取屬性
    /@attrName     ==>img/src

案例

彼岸圖片爬取

import requests
from lxml import etree

if __name__ == "__main__":
    url = 'https://pic.netbian.com/4k/index_61.html'
    headers = {
        'user-agent': 'Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36'
    }
    response = requests.get(url=url, headers=headers)
    response.encoding = "GBK"
    tree = etree.HTML(response.text)
    img_all_url = tree.xpath('//ul[@class="clearfix"]//img/@src')
    for img_url in img_all_url:
        url = "https://pic.netbian.com" + img_url
        img_content = requests.get(url=url, headers=headers).content
        img_name = url.split("/")[-1]
        with open(f"彼岸圖/{img_name}","wb") as f:
            f.write(img_content)

    print("over")

模擬登陸

1.建立session物件:

session = reuqests.Session()

2.使用session物件進行模擬登入post請求的傳送

session.post(headers=headers,url=url)

代理ip

破解封ip這種反爬機制

代理伺服器

作用:

​ 1. 突破自身IP訪問的限制

​ 2.隱藏自身真實的IP

代理ip型別:

​ http:應用到http協議對應的url中

​ https:應用到https協議對應的url中

代理ip的匿名度;

​ 透明:伺服器知道該次請求使用代理,也知道請求對應的真實ip

​ 匿名:知道使用了代理,不知道真實ip

​ 高匿:不知道使用了代理,更不知道真實的ip

使用

proxies = {
    "http": '49.85.112.173:7890'
}

requests.get(url=url, headers=headers, proxies=proxies, params=params)

例項:

import requests

url = 'https://www.baidu.com/s'
headers = {
    "user-agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36"
}

proxies = {
    "http": '49.85.112.173:7890'
}
wd = input("請輸入搜尋的內容:")
params = {
    'ie': 'utf-8',
    'f': '8',
    'rsv_bp': 1,
    'rsv_idx': 1,
    'tn': 'baidu',
    'wd': wd,
}
response = requests.get(url=url, headers=headers, proxies=proxies, params=params).text
print(response)
print("over")

高效能非同步爬蟲

在爬蟲中使用非同步實現高效能的資料爬取操作

多執行緒,多程序(不建議)

​ 好處:可以為相關堵塞的操作單獨開啟執行緒或程序,堵塞操作就可以非同步執行。

​ 弊端:無法無限制的開啟多執行緒或者多程序。

執行緒池、程序池(適當使用)

​ 好處:我們可以降低系統對程序或者 執行緒和銷燬一個頻率,從而更好的降低系統的開銷。

​ 弊端:池中執行緒或程序的數量是有上限。

案例執行緒池

# 梨視訊爬取
import requests
from multiprocessing.dummy import Pool
import time
from lxml import etree

start_time = time.time()
headers = {
    "user-agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36"
}

url = "https://www.pearvideo.com/category_5"
response = requests.get(url=url, headers=headers).text
tree = etree.HTML(response)
all_href = tree.xpath('//ul[@id="categoryList"]/li/div/a/@href')
video_all_list = []
for href in all_href:
    video_url = "https://www.pearvideo.com/" + href
    video_dic = {"contId": href.split("_")[1], "url": video_url}
    video_all_list.append(video_dic)


def down_img(data_list):
    json_headers = {
        "user-agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36",
        "Referer": data_list["url"]  # 防盜鏈
    }
    contId = data_list["contId"]
    video_json_url = f"https://www.pearvideo.com/videoStatus.jsp?contId={contId}"
    response_json = requests.get(url=video_json_url, headers=json_headers).json()
    mp4_url = response_json["videoInfo"]["videos"]["srcUrl"]
    cont = f"cont-{contId}"
    real_url = mp4_url.replace(mp4_url.split("-")[0].split("/")[-1], cont)
    print(f"正在下載{contId}")
    mp4_content = requests.get(url=real_url, headers=json_headers).content
    with open(f"梨視訊/{contId}.mp4", "wb") as f:
        f.write(mp4_content)
        print(f"下載完成{contId}")


pool = Pool(8)  # 建立8個執行緒池
pool.map(down_img, video_all_list)
pool.close()  # 關閉執行緒池
pool.join() # 主程序堵塞後 讓子程序繼續進行完成,子程序完成後,再把主程序全部關閉
now = time.time()
print(f"用時{now - start_time}")

"""
 json_headers = {
        "user-agent": "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 94.0.4606.61Safari / 537.36",
        "Referer": data_list["url"]  # 防盜鏈
    }
    
 data_list是一個列表
 pool.map(down_img, video_all_list)
 當執行到這段程式碼時
 相當於
 for data_list in data_list
 所有能從data_list通過key取值value
 """

非同步協程

1.用async修飾一個函式,呼叫之後返回一個協程物件

2.將協程封裝到Task物件中並新增到事件迴圈的任務列表中,等待事件迴圈去執行

3.建立一個事件迴圈物件

4.將協程物件註冊到loop中,啟動loop

import requests
import asyncio
import time
import aiohttp

urls = []
start = time.time()
for i in range(10):
    urls.append('http://127.0.0.1:5000/bobo')
print(urls)


async def get_page(url):  # async修飾一個函式
    async with aiohttp.ClientSession() as session:
        # get()、post():
        # headers,params/data,proxy='http://ip:port'
        async with await session.get(url) as response:
            # text()返回字串形式的響應資料
            # read()返回的二進位制形式的響應資料
            # json()返回的就是json物件
            
            # 注意:獲取響應資料操作之前一定要使用await進行手動掛起
            page_text = await response.text()
            print(page_text)


tasks = []

for url in urls:
    c = get_page(url)  # 返回一個協程物件
    task = asyncio.ensure_future(c) 
    tasks.append(task) #  將協程封裝到Task物件中並新增到事件迴圈的任務列表中

方法一:
    '''
    loop = asyncio.get_event_loop() # 建立一個事件迴圈物件
    result = asyncio.wait(tasks)
    loop.run_until_complete(result) # 將協程物件註冊到loop中,啟動loop
    '''
 方法二:
    '''
    本質上方式一是一樣的,內部先 建立事件迴圈 然後執行 run_until_complete,一個簡便的寫法。
    python 3.7
    result = asyncio.wait(tasks)
    asyncio.run(result)
    '''
end = time.time()

print('總耗時:', end - start)

標籤定位

#執行一組js程式
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')

#點選搜尋按鈕
bro.find_element_by_css_selector('.btn-search').click()
#回退
bro.back()
sleep(2)
#前進
bro.forward()
# 關閉瀏覽器
bro.quit()
bro.close()
#標籤互動
search_input = bro.find_element_by_id('q')
search_input.send_keys('Iphone') # 如果是input標籤將在標籤中輸入Iphone


#匯入動作鏈對應的類
from selenium.webdriver import ActionChains

#動作鏈
action = ActionChains(bro)
#點選長按指定的標籤
action.click_and_hold(div)
# 移動動作鏈  x軸17 y軸0
action.move_by_offset(17,0).perform()
#釋放動作鏈
action.release()


#如果定位的標籤是存在於iframe標籤之中的則必須通過如下操作在進行標籤定位
bro.switch_to.frame('iframeResult') # 切換瀏覽器標籤定位的作用域
bro.switch_to.frame(定位ifrme元素)

selenium

from selenium import webdriver
from time import sleep
#實現無視覺化介面
from selenium.webdriver.chrome.options import Options
#實現規避檢測
from selenium.webdriver import ChromeOptions

#實現無視覺化介面的操作
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

#實現規避檢測
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])

#如何實現讓selenium規避被檢測到的風險
bro = webdriver.Chrome(executable_path='./chromedriver',chrome_options=chrome_options,options=option)

#無視覺化介面(無頭瀏覽器 不彈出瀏覽器) phantomJs
bro.get('https://www.baidu.com')

print(bro.page_source)
sleep(2)
bro.quit()

12306模擬登入

from selenium import webdriver
import time
from selenium.webdriver.support import wait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Chrome(r"chromedriver_win32/chromedriver.exe")
driver.get("https://kyfw.12306.cn/otn/resources/login.html")
driver.find_element_by_xpath('//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a').click()
driver.find_element_by_id("J-userName").send_keys(15237674912)
time.sleep(0.5)
driver.find_element_by_id('J-password').send_keys(""*******")
driver.find_element_by_id('J-login').click()
# 關閉selenium不可使用滑塊的限制
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
driver.execute_script(script)
# 等待5秒時間家長出類  nc_iconfont.btn_slide
slide_btn = wait.WebDriverWait(driver, 5).until(
    EC.presence_of_element_located((By.CLASS_NAME, 'nc_iconfont.btn_slide')))
# click_and_hold按住滑鼠左鍵在源元素上,點選並且不釋放
ActionChains(driver).click_and_hold(on_element=slide_btn).perform()
# move_by_offset向右移動 x軸300 y軸0
ActionChains(driver).move_by_offset(xoffset=300, yoffset=0).perform()

12306登入老版 超級鷹驗證

# 下述程式碼為超級鷹提供的示例程式碼
import requests
from hashlib import md5


class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password = password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 圖片位元組
        codetype: 題目型別 參考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files,
                          headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:報錯題目的圖片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


# chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')   #使用者中心>>軟體ID 生成一個替換 96001
# im = open('12306.jpg', 'rb').read()                                      #本地圖片檔案路徑 來替換 a.jpg 有時WIN系統須要//
# print(chaojiying.PostPic(im, 9004)['pic_str'])
# 上述程式碼為超級鷹提供的示例程式碼

# 使用selenium開啟登入頁面
from selenium import webdriver
import time
from PIL import Image
from selenium.webdriver import ActionChains

bro = webdriver.Chrome(executable_path='./chromedriver')
bro.get('https://kyfw.12306.cn/otn/login/init')
time.sleep(1)

# save_screenshot就是將當前頁面進行截圖且儲存
bro.save_screenshot('aa.png')

# 確定驗證碼圖片對應的左上角和右下角的座標(裁剪的區域就確定)
code_img_ele = bro.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img')
location = code_img_ele.location  # 驗證碼圖片左上角的座標 x,y
print('location:', location)
size = code_img_ele.size  # 驗證碼標籤對應的長和寬
print('size:', size)
# 左上角和右下角座標
rangle = (
    int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
# 至此驗證碼圖片區域就確定下來了

i = Image.open('./aa.png')
code_img_name = './code.png'
# crop根據指定區域進行圖片裁剪
frame = i.crop(rangle)
frame.save(code_img_name)

# 將驗證碼圖片提交給超級鷹進行識別
chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')  # 使用者中心>>軟體ID 生成一個替換 96001
im = open('code.png', 'rb').read()  # 本地圖片檔案路徑 來替換 a.jpg 有時WIN系統須要//
print(chaojiying.PostPic(im, 9004)['pic_str'])
result = chaojiying.PostPic(im, 9004)['pic_str']
all_list = []  # 要儲存即將被點選的點的座標  [[x1,y1],[x2,y2]]
if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
        xy_list = []
        x = int(list_1[i].split(',')[0])
        y = int(list_1[i].split(',')[1])
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)
print(all_list)
# 遍歷列表,使用動作鏈對每一個列表元素對應的x,y指定的位置進行點選操作
for l in all_list:
    x = l[0]
    y = l[1]
    ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
    time.sleep(0.5)

bro.find_element_by_id('username').send_keys('[email protected]')
time.sleep(2)
bro.find_element_by_id('password').send_keys('bobo_15027900535')
time.sleep(2)
bro.find_element_by_id('loginSub').click()
time.sleep(30)
bro.quit()

scrapy框架

環境的安裝

 python
   - mac or linux:
   		pip install scrapy
   - windows:
          pip install wheel
          # 下載twisted,下載地址為http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
          # 安裝twisted:pip install Twisted‑17.1.0‑cp36‑cp36m‑win_amd64.whl
          pip install pywin32
          pip install scrapy
  ```

基礎指令

建立一個工程:
    scrapy startproject xxxPro
         cd xxxPro  # 切換到這個工程
         在spiders子目錄中建立一個爬蟲檔案
            scrapy genspider spiderName www.xxx.com
         執行工程:
             scrapy crawl spiderName

持久化儲存

基於終端

基於終端指令:
        - 要求:只可以將parse方法的返回值儲存到本地的文字檔案中
        - 注意:持久化儲存對應的文字檔案的型別只可以為:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle
        - 指令:scrapy crawl xxx -o filePath
        - 好處:簡介高效便捷
        - 缺點:侷限性比較強(資料只可以儲存到指定字尾的文字檔案中)

基於管道

  1. 在items.py 中封裝屬性物件

    import scrapy
    # 封裝了 content time 2個物件
    
    class DuanziproItem(scrapy.Item):
        # define the fields for your item here like:
        content = scrapy.Field()
        time = scrapy.Field()
    
    
  2. 將解析到資料值儲存到items物件

    duanzi.py

    item = DuanziproItem()
    item['time'] = time
    item['content'] = content
    
  3. 在管道檔案中編寫程式碼完成資料儲存的操作

    pipelines.py

    class DuanziproPipeline:
        fp = None
    
        # 重寫父類的一個方法:該方法只在開始爬蟲的時候被呼叫一次
        def open_spider(self, spider):
            print('開始爬蟲......')
            self.fp = open('./duanzi.txt', 'w', encoding='utf-8')
    
        # 專門用來處理item型別物件
        # 該方法可以接收爬蟲檔案提交過來的item物件
        # 該方法沒接收到一個item就會被呼叫一次
        def process_item(self, item, spider):
            time = item['time']
            content = item['content']
    
            self.fp.write(time + ':' + content + '\n')
    
            return item  # 就會傳遞給下一個即將被執行的管道類
    
        def close_spider(self, spider):
            print('結束爬蟲!')
            self.fp.close()
    
  4. 在配置檔案settings.py中開啟管道操作

ITEM_PIPELINES = {
    'duanziPro.pipelines.DuanziproPipeline': 300,
}

儲存到資料庫

duanzi.py

import scrapy
from ..items import DuanziproItem


class DuanziSpider(scrapy.Spider):
    name = 'duanzi'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://duanzixing.com/']

    def parse(self, response):
        all_content = response.xpath('//article[@class="excerpt"]//h2/a/text()').extract()
        all_time = response.xpath('//p[@class="meta"]/time/text()').extract()
        for i in range(0, len(all_time)):
            time = all_time[i]
            content = all_content[i]
            item = DuanziproItem()
            item['time'] = time
            item['content'] = content
            # 2.將item物件提交給管道
            yield item

在item.py中封裝物件

import scrapy
# 封裝了 content time 2個物件

class DuanziproItem(scrapy.Item):
    # define the fields for your item here like:
    content = scrapy.Field()
    time = scrapy.Field()

pipelines.py 增加一個類

import pymysql


class QiubaiproPipeline(object):
    conn = None  # mysql的連線物件宣告
    cursor = None  # mysql遊標物件宣告

    def open_spider(self,spider):
        print('開始爬蟲')

        # 連結資料庫
        # host 本機的ip地址
        # 在命令列輸入 ipconfig檢視
        self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='',db='duanzi',charset='utf8')


    # 該方法可以接受爬蟲檔案中提交過來的item物件,並且對item物件的頁面資料進行持久化處理
    # 引數:item表示的就是接受到的item物件
    def process_item(self, item, spider):
        # 1.連結資料庫
        # 執行sql語句


        # 插入資料
        sql = 'insert into db1(time,content) values("%s","%s")'%(item['author'], item['content'])
        # 獲取遊標
        self.cursor = self.conn.cursor()
        try:
            self.cursor.execute(sql)
            self.conn.commit()
        except Exception as e:
            print(e)
            self.conn.rollback()

        # 提交事務
        return item
    # 該方法只會在爬蟲結束的時候被呼叫一次
    def close_spider(self,spider):
        print('爬蟲結束')
        self.cursor.close()
        self.conn.close()

Spider的全站資料爬取

通過定製一個url模板

使用模板自定義修改獲取一個新的url 回撥 parse()

yield scrapy.Request(url=new_url, callback=self.parse)

# 彼岸圖爬取
import scrapy


class BiantuSpider(scrapy.Spider):
    name = 'biantu'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://pic.netbian.com/index_1.html']
    # 定製模板
    url = "https://pic.netbian.com/index_%d.html"
    page_num = 2

    def parse(self, response):
        alt_list = response.xpath('//ul[@class="clearfix"]/li/a/img/@alt').extract()
        for title in alt_list:
            print(title)

        if self.page_num <= 5:
            new_url = format(self.url % self.page_num)
            self.page_num += 1
            # 回撥 parse函式
            yield scrapy.Request(url=new_url, callback=self.parse)

五大核心

  1. 引擎(Scrapy)
    用來處理整個系統的資料流處理, 觸發事務(框架核心)

  2. 排程器(Scheduler)
    用來接受引擎發過來的請求, 壓入佇列中, 並在引擎再次請求的時候返回. 可以想像成一個URL(抓取網頁的址 或者說是連結)的優先佇列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址
    下載器(Downloader)
    用於下載網頁內容, 並將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的非同步模型上的)

  3. 爬蟲(Spiders)
    爬蟲是主要幹活的, 用於從特定的網頁中提取自己需要的資訊, 即所謂的實體(Item)。使用者也可以從中提取出連結,讓Scrapy繼續抓取下一個頁面

  4. 專案管道(Pipeline)
    負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的資訊。當頁面被爬蟲解析後,將被髮送到專案管道,並經過幾個特定的次序處理資料。