????????現在的PC、手機客戶端等終端設備大量使用了網頁前后端技術,另外主流的網站也會經常會更新,導致以前一個月更新一次爬蟲代碼,變成了天天需要更新代碼,所以自動化爬蟲技術在當前就顯得特別重要,最近我也是在多次更新某個爬蟲后,突然有了這樣的需求,嘗試搜索了下相關信息,發現是有人弄過這東西,我想哪些大廠肯定也有爬蟲工程師開發過這東西,但是都沒有開源,找不到啥資料,所以我想寫一篇這方面的東西,感興趣的朋友可以看下去。
? ? ? ? 首先,我們先確定下基本思路,我經常使用Requests+BeautifulSoup寫爬蟲,所以基本代碼的模板很好寫,如下:
code_template = """
import requests
from bs4 import BeautifulSoupdef crawl(url):response = requests.get(url)response.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')results = []SELECTORS_PLACEHOLDERreturn resultsif __name__ == "__main__":url = "URL_PLACEHOLDER"results = crawl(url)for result in results:print(result)"""
其中SELECTORS_PLACEHOLDER就是我們需要用程序動態填寫的內容,這是根據爬蟲自我填寫的代碼,輸入的代碼如下所示:?那么我們跟這個程序根據什么爬蟲那,其實也很簡單,我們使用上一篇文章的例子,鏈接如下為:
Python爬蟲系列-爬取小說20240703更新(Request方法)https://blog.csdn.net/donglxd/article/details/140145498
我們先試試爬取某個章節部分,隨便打開一篇文章,如下圖:
選取一行字,比如正文的第一句:"京海市第四高中,新生報到日。" 把這句作為一個參數代入到我的程序中,同時把這篇文章的網址也代入到我的程序中如下:
把運行后的自動寫的代碼如下:
復制后新建一個python文件,粘貼進去,保存并運行,就會得到如下結果:
?
有人要問了,我的自動生成爬蟲,只能爬取文本嗎?不能爬取屬性值嗎?比如屬性里的鏈接?當然可以,請看下圖:
可以看到第一章的鏈接是"41594870.html",這個不是絕對鏈接,而是相對鏈接,需要拼接處理,這個很簡單,我想稍微學過5分鐘python字符串語法的都會。我們把這個"41594870.html"屬性代入我的程序讀取看看,參數設置如下:
生成的爬蟲如下:新建一個python文檔運行看看:
可以看到爬取成功了,我們可以嘗試把兩者結合起來,寫一個手動爬蟲,如下:
import requests
from bs4 import BeautifulSoup
import time# 導入time庫加延遲用# def crawl(url):
def getText(url):#把crawl函數建立一個新名稱,方便調用,這個函數和下面的函數名不同,已區分開功能(讀取每章內容)response = requests.get(url)response.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')# results = []results = ""#把數組改成字符串拼接用elements = soup.select('html body #main .bookinfo.m10.clearfix .chaptercontent #content p')for element in elements:# results.append(element.get_text(strip=True))results = results + element.get_text(strip=True) + "\n"results = results + "\n"#每章之間空一行return results# def crawl(url):
def getUrl(url):#把crawl函數建立一個新名稱,方便調用,這個函數和下面的函數名不同,已區分開功能(讀取每章網址)response = requests.get(url)response.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')# results = []elements = soup.select('html body #main .chapterlist .clearfix li a')with open("20.AI編程爬蟲\\1.txt","a+",encoding="utf-8") as f:# 創建一個新的txt文檔,記錄小說內容。for element in elements:# results.append(element.get('href', 'N/A'))results = getText(url + "/" + element.get('href', 'N/A'))# 把主鏈接和href的相對鏈接拼合f.write(results)#寫入每章內容到txt文檔print("鏈接內容:" + url + "/" + element.get('href', 'N/A') + "寫入成功!")#輸出寫入的鏈接time.sleep(3)#為了爬取穩定加點延遲# return resultsif __name__ == "__main__":url = "https://www.feibzw.com/Html/51366"# results = getUrl(url)getUrl(url)# for result in results:# print(result)
可以看到上面的代碼中,我注釋的代碼都是原來兩個爬蟲里的,新加的代碼都有注釋說明,一行行寫下來不難,這部分其實也可以自動化,但是可能每個網站的鏈接地址都不同,拼接方法也不同,所以我寫了這個模板給大家套用,按實際情況改就行了,這個模板可以應付大多數小說網站。我在這只是教大家方法,希望有拋磚引玉的作用,授人以漁。
最后放上我的自動生成程序,免費提供給大家:
import requests
from bs4 import BeautifulSoupdef find_elements_by_text_or_attribute(url, text):# 發送請求并獲取網頁內容response = requests.get(url)response.raise_for_status() # 檢查請求是否成功html_content = response.text# 解析網頁內容soup = BeautifulSoup(html_content, 'html.parser')# 查找所有包含目標文本的標簽target_tags = set()for tag in soup.find_all(string=True):if text in tag:parent = tag.parenttarget_tags.add(parent)# 查找所有包含目標屬性值的標簽for tag in soup.find_all(True): # True表示查找所有標簽for attr, value in tag.attrs.items():if isinstance(value, list):value = ' '.join(value)if text in value:target_tags.add(tag)breakreturn target_tagsdef get_unique_selectors(target_tags):unique_selectors = set()for tag in target_tags:selectors = []for parent in tag.parents:if parent.name == '[document]':breakif parent.get('id'):selectors.append(f"#{parent.get('id')}")elif parent.get('class'):selectors.append(f".{'.'.join(parent.get('class'))}")else:selectors.append(parent.name)selectors.reverse()selectors.append(tag.name)unique_selector = ' '.join(selectors)unique_selectors.add(unique_selector)return unique_selectorsdef generate_crawler_code(url, selectors, is_attribute, attribute=None):code_template = """
import requests
from bs4 import BeautifulSoupdef crawl(url):response = requests.get(url)response.raise_for_status()soup = BeautifulSoup(response.text, 'html.parser')results = []SELECTORS_PLACEHOLDERreturn resultsif __name__ == "__main__":url = "URL_PLACEHOLDER"results = crawl(url)for result in results:print(result)"""selectors_code = ""for selector in selectors:selectors_code += f"elements = soup.select('{selector}')\n"selectors_code += f" for element in elements:\n"if is_attribute:selectors_code += f" results.append(element.get('{attribute}', 'N/A'))\n" # 這里的N/A表示如果屬性不存在返回默認值else:selectors_code += f" results.append(element.get_text(strip=True))\n"final_code = code_template.replace("URL_PLACEHOLDER", url).replace("SELECTORS_PLACEHOLDER", selectors_code)return final_codedef crawl_generator(url, text):target_tags = find_elements_by_text_or_attribute(url, text)if target_tags:unique_selectors = get_unique_selectors(target_tags)attribute = Noneis_attribute = False# 檢查是文本內容還是屬性值for tag in target_tags:for attr, value in tag.attrs.items():if isinstance(value, list):value = ' '.join(value)if text in value:is_attribute = Trueattribute = attrbreakif is_attribute:breakcrawler_code = generate_crawler_code(url, unique_selectors, is_attribute, attribute)return crawler_codeelse:return "未找到包含目標文本或屬性的元素。"if __name__ == "__main__":url = "https://www.feibzw.com/Html/51366" # 替換為目標網址text = "41594870.html" # 替換為目標文本# url = "https://www.feibzw.com/Html/51366/41594870.html" # 替換為目標網址# text = '''京海市第四高中,新生報到日。''' # 替換為目標文本crawler_code = crawl_generator(url, text)print(crawler_code)
謝謝大家觀看,再見!?