頂點小說
裝xpath helper
GitHub - mic1on/xpath-helper-plus: 這是一個xpath開發者的工具,可以幫助開發者快速的定位網頁元素。
Question:載入完外掛點選沒反應
Answer:將開發人員模式關閉即可
爬蟲介紹
分類:
- 搜尋引擎:爬取範圍廣
- 聚焦爬蟲:爬取範圍聚焦
介紹:
程式發起請求(request),獲取響應(response),解析response中的資料
URL
即統一資源定位符
組成:
- 協議
- http
- https:新增SSL協議(證書驗證),之前花錢,現在開源了,所以大部分網站都是https,據說效能損耗,但忽略不計
- 主機IP地址(有時也包括埠號)
- 主機資源具體地址:如目錄和檔名等
靜態網站和動態網站
- 靜態網站:資料在頁面原始碼中
- 動態網站:資料在介面中,網站透過ajax請求介面獲取資料,再透過js鑲在頁面中
結構化與非結構化資料
- 結構化資料:可以用關係型資料庫表示和儲存,表現為二維形式的資料
- 非結構化資料:資料結構不規則,不方便用二位邏輯來表現,如辦公文件、圖片、HTML、音訊和影片等等
xpath
概念:即為XML路徑語言(XML Path Language),用於確定XML文件中某部分位置的語言,python可以使用xpath的語法定位html文件中某部分的位置,並進行抽取
示例:xpath是抽取靜態網站資料的常用方法
Question:動態網站可以用xpath進行解析嗎?
Answer:
動態網站採用了ajax技術,ajax發起請求對頁面進行替換分為 整塊替換和 部分替換,部分替換則介面返回資料格式為Json,整塊替換則介面返回html文件
如果返回html文件,則可用xpath進行解析,如果返回Json資料,則不可用xpath進行解析
總結:xpath是否可進行解析取決於資料是否為結點資料(是否具有結點),JSON為字串,肯定不可用xpath進行解析
語法:
- /:從文件根目錄開始選取
- //:全域性進行查詢選取,//代表前面有東西,但不重要,相當於正規表示式的 .*?
- //li/a/text():可以獲取小說的所有書名,然後透過python進行切片獲取具體的個別資料
- //li//text():可以獲取 li 標籤下的所有文字(不區分什麼標籤),只限深度為1
- //a[@class="poptext"]:可以選取帶有 class屬性 的 a標籤
- @href:可以獲取此元素的 href屬性值
- *:匹配任何元素結點,如//*、/bookstore/*
- |:類似and,都獲取,如//book/title | //book/price
案例:頂點小說抓取
-
導包,定義headers(有的小說網站對headers無要求,有的有要求)
import requests from lxml import etree import pymysql # headers headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0" }
-
獲取小說分類url
# 獲取小說分類url def get_type(): url = "https://www.cdbxs.com/sort/" source = requests.get(url=url, headers=headers).content.decode('utf-8') href_lists = etree.HTML(source).xpath('//ul[@class="nav"]/li/a/@href')[2:-4] type_lists = [] for href in href_lists: type_lists.append(f"{url}{href.split('/')[2]}/1/") # print(type_lists) return type_lists
-
獲取最大頁
# 獲取最大頁 def get_max_page(first_page_url): source = requests.get(url=first_page_url, headers=headers).content.decode('utf-8') # print(source) max_page = etree.HTML(source).xpath('//a[13]/text()') return max_page
-
獲取每個分類的每一頁url
# 獲取小說分類url type_lists = get_type() # 分類url預設為第一頁 for first_page_url in type_lists: # 獲取帶分類的url的前半截 type_url = first_page_url.split('1')[0] # 獲取此分類下最大頁 max_page = get_max_page(first_page_url) # 生成此分類下每一頁url for every_page in range(1, int(max_page[0])+1): every_page_url = f"{type_url}{every_page}/" print(every_page_url)
-
獲取小說列表頁資訊
def get_book_info(every_page_url): source = requests.get(url=every_page_url, headers=headers).content.decode('utf-8') book_lists = [] lis = etree.HTML(source).xpath("//ul[@class='txt-list txt-list-row5']/li") for li in lis: book_id_url = li.xpath("span[@class='s2']/a/@href")[0] book_id = book_id_url.split('/')[3] # 書名 book_name = li.xpath("span[@class='s2']/a/text()")[0] # 最新章節 new_chapter = li.xpath("span[@class='s3']/a/text()")[0] # 作者 author = li.xpath("span[@class='s4']/text()")[0] # 更新時間 update_time = li.xpath("span[@class='s5']/text()")[0] source = requests.get(url=f"https://www.cdbxs.com{book_id_url}", headers=headers).content.decode('utf-8') # 字數 font_num = etree.HTML(source).xpath("//p[6]/span/text()")[0] # 摘要 summary = etree.HTML(source).xpath("//div[@class='desc xs-hidden']/text()")[0] # 以元組新增至 book_lists # print((book_id, book_name, new_chapter, author, update_time, font_num, summary)) book_lists.append((book_id, book_name, new_chapter, author, update_time, font_num, summary)) return book_lists
-
獲取章節列表url
# 獲取章節列表url def get_chapter_urls(chapter_list_url): source = requests.get(url=chapter_list_url, headers=headers).content.decode('utf-8') # 章節url chapter_urls = map(lambda x: "https://www.cdbxs.com" + x, etree.HTML(source).xpath("//div[@class='section-box'][2]/ul[@class='section-list fix']/li/a/@href | //div[@class='section-box'][1]/ul[@class='section-list fix']/li/a/@href")) return chapter_urls
-
獲取章節詳情資訊
# 獲取章節詳情資訊 def get_chapter_info(chapter_url): source = requests.get(url=chapter_url, headers=headers).content.decode('utf-8') # 標題 title = etree.HTML(source).xpath("//h1[@class='title']/text()") # 正文 content = ''.join(etree.HTML(source).xpath("//div[@id='nb_content']/dd//text()")) if title: return title[0], content else: return '', content
-
整合
# 獲取小說分類url type_lists = get_type() # 分類url預設為第一頁 for first_page_url in type_lists: # 獲取帶分類的url的前半截 type_url = first_page_url.split('1')[0] # 獲取此分類下最大頁 max_page = get_max_page(first_page_url) # 生成此分類下每一頁url for every_page in range(1, int(max_page[0]) + 1): every_page_url = f"{type_url}{every_page}/" # 獲取小說列表頁資訊 book_info_lists = get_book_info(every_page_url) # 獲取章節列表url for book_info in book_info_lists: print(f"爬取小說:{book_info[1]}...") book_id = book_info[0] chapter_urls = get_chapter_urls(f"https://www.cdbxs.com/booklist/b/{book_id}/1") for chapter_url in chapter_urls: # print(chapter_url) chapter_info = get_chapter_info(chapter_url) print(chapter_info) print(chapter_info[0]) print(chapter_info[1]) # print(f"title:{chapter_info[0]}") # print(f"content:{chapter_info[1]}")
注:關注我,後續會陸續出爬蟲內容(包括但不僅限於頂點小說進階:資料入庫、多執行緒多程序爬取資料)