多線程爬蟲其實很簡單,只用十個線程每天即可爬取100萬條數據

前言

由於頭條對代碼塊實在是太不友好,所以上傳的代碼直接複製可能無法使用,需要自行調整,如果需要源代碼的話,就私信我吧,另外給個關注唄,謝謝各位,共同學習,共同進步!

多線程爬蟲其實很簡單,只用十個線程每天即可爬取100萬條數據

今天還是實戰的一天,首先這次爬取的是房價信息,爬取網站為安居客,由於安居客的反爬機制不是很強,所以隨便弄幾個代理服務器就可以隨便爬取任何數據,這一次也是利用多線程花了一天時間,爬了100多萬條數據,由於電腦配置不怎麼好,只開了十個線程,速度也是槓槓滴,而且阻塞問題也基本不存在,如果開的線程太多存在阻塞問題的話,那需要各位自己再進行異步存儲了!

爬蟲環境

Pycharm+python3.7.0

多線程爬蟲其實很簡單,只用十個線程每天即可爬取100萬條數據

當你看到自己編寫的程序像蜘蛛一樣在網絡上快速爬行,為你尋找你需要的數據的時候,那種滋味絕對很爽,不廢話,還是上代碼!

"""
使用併發爬取一定要注意網站要驗證等問題
不然影響爬蟲進度
另外代理的話也要多一點
壽命不長沒關係,很快就能爬取完
長期代理爬取速度太快需要謹慎
不然容易被馬上查到
併發在一般同步爬取的基礎上加入併發加速器,多線程進行爬取
"""

# 老規矩,導入需要的庫文件
# 導入請求庫,用於向網站發送請求
import requests
# 導入解析庫,用於解析html文檔
from bs4 import BeautifulSoup
# 導入時間模塊,用於模擬人類操作
import time
# 導入加速器模塊以及相關庫
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
# 導入csv模塊,用於讀寫csv文件
import csv

# 開始時間,用於計算程序運行時間
t1 = time.time()
print('#' * 50)

# 加入代理,這個代理是我自己購買的,需要的話自行購買,這個不能使用了
proxy = "[email protected]:28803"
proxies = {
 'http': 'http://' + proxy,
 'https': 'https://' + proxy
}

# 加入請求頭,模擬瀏覽器端登錄網站
headers = {
 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'}


# 定義函數獲取每個網頁以及需要爬取的內容,以下是我在安居網需要爬取的內容
def parser(url):
 res = requests.get(url, headers=headers)
 # 對響應體進行解析
 soup = BeautifulSoup(res.text, "lxml")
 # 找到頁面子鏈接,進入子頁面,對子頁面進行抓取
 # 用select函數抽取需要的內容,單擊需要的內容》檢查》copy select
 titles = soup.select("#houselist-mod-new > li > div.house-details > div.house-title > a") # 標題
 addresses = soup.select(
 "#houselist-mod-new > li > div.house-details > div:nth-child(3) > span.comm-address") # 地址
 dprices = soup.select("#houselist-mod-new > li > div.pro-price > span.unit-price") # 日租價格
 tprices = soup.select("#houselist-mod-new > li > div.pro-price > span.price-det > strong") # 月租價格
 areas = soup.select(
 "#houselist-mod-new > li > div.house-details > div:nth-child(2) > span:nth-child(3)") # 面積大小
 years = soup.select(
 '#houselist-mod-new > li > div.house-details > div:nth-child(2) > span:nth-child(7)') # 抽取建造年份
 lous = soup.select("#houselist-mod-new > li > div.house-details > div:nth-child(2) > span:nth-child(5)") # 樓層屬性
 tings = soup.select(
 '#houselist-mod-new > li > div.house-details > div:nth-child(2) > span:nth-child(1)') # 抽取廳室特點
 traffics = soup.select('#houselist-mod-new > li > div.house-details > div.tags-bottom') # 抽取交通情況
 for title, address, dprice, tprice, area, year, lou, ting, traffic in zip(titles, addresses, dprices, tprices,
 areas, years, lous, tings, traffics):
 # 建立空列表,分配存儲地址
 dprice = dprice.text, # 價格直接獲取裡面的文本就可以,兩邊是標籤
 dprice = dprice[0].strip("元/m²")
 tprice = tprice.text, # 價格直接獲取裡面的文本就可以,兩邊是標籤
 tprice = tprice[0]
 title = title.text.strip(), # 獲得文本並去除掉文本兩側的不必要的字符,用strip()
 address = address.text.strip() # 同樣地址也是去除兩頭不必要的字符串
 address = address.split('\xa0\xa0\n'),
 address = address[0][0] + address[0][1].strip(),
 area = area.text,
 area = area[0],
 year = year.text,
 lou = lou.text,
 ting = ting.text,
 traffic = traffic.text.strip('\n')
 data = [title[0], address[0], dprice, tprice, area[0], year[0], lou[0], ting[0], traffic] # 將以上數據放入列表中打印在命令框
 print(data)
# 將數據寫入csv文件中,這裡就是IO操作,容易阻塞,大家要注意
 with open('二手房/最新8.14/華北東北/保定.csv', 'a', newline='',
 encoding='utf-8-sig') as csvfile:
 w1 = csv.writer(csvfile)
 w1.writerow(data)
# 讓程序睡眠一秒鐘
 # time.sleep(1)

# 給出我們需要爬取的網站
urls = ['https://baoding.anjuke.com/sale/o5-p{}/#filtersort'.format(number) for number in range(1, 51)]

# 這裡是一些城市
"""
cities = [
 {'成都':'chengdu', '重慶':'chongqing', '武漢':'wuhan', '鄭州':'zhengzhou', '西安':'xa', '昆明':'km', 
 '貴陽':'gy', '蘭州':'lanzhou', '洛陽':'luoyang'}, 
 
 {'深圳':'shenzhen', '廣州':'guangzhou', '佛山':'foshan', '長沙':'cs', '三亞':'sanya', '惠州':'huizhou', 
 '東莞':'dg', '海口':'haikou', '珠海':'zh', '中山':'zs', '廈門':'xm', '南寧':'nanning', '泉州':'quanzhou', 
 '柳州':'liuzhou'},
 
 {'上海':'shanghai', '杭州':'hangzhou', '蘇州':'suzhou', '南京':'nanjing', '無錫':'wuxi', '濟南':'jinan', 
 '青島':'qingdao', '崑山':'ks', '寧波':'nb', '南昌':'nc', '福州':'fz', '合肥':'hf', '徐州':'xuzhou', 
 '淄博':'zibo', '南通':'nantong', '常州':'cz', '湖州':'huzhou'},
 
 {'北京':'beijing', '天津':'tianjin', '大連':'dalian', '石家莊':'sjz', '哈爾濱':'heb', '瀋陽':'sy', 
 '太原':'ty', '長春':'cc', '威海':'weihai', '濰坊':'weifang', '呼和浩特':'huhehaote', '包頭':'baotou', '秦皇島':'qinhuangdao', 
 '煙臺':'yt', '保定':'baoding'}
 ]
"""

# 利用併發加速爬取,最大線程為50個,本文章中一共有50個網站,可以加入50個線程
# 建立一個加速器對象,線程數每個網站都不同,太大網站接受不了會造成數據損失
executor = ThreadPoolExecutor(max_workers=10)

# submit()的參數: 第一個為函數, 之後為該函數的傳入參數,允許有多個
future_tasks = [executor.submit(parser, url) for url in urls]

# 等待所有的線程完成,才進入後續的執行
wait(future_tasks, return_when=ALL_COMPLETED)

# 計算總用時間
t2 = time.time() # 結束時間
print('併發方法,總共耗時:%s' % (t2 - t1))
print('#' * 50)
# 本來需要十幾分鐘的爬蟲,利用併發只需要一分鐘就可以爬取完成,十分迅速

 
多線程爬蟲其實很簡單,只用十個線程每天即可爬取100萬條數據

其實多線程是很簡單的,就是在原來同步爬取的基礎上,給主函數加入一些線程,也就是本來這件事情是一個人乾的,現在我讓10個人來做,那就是10個線程,速度肯定提高一大截,只要理解其中的原理,代碼什麼的就迎刃而解了;

需要源代碼的私信就好,以後基本每天或者隔幾天會發佈一個項目實戰,其實一個代碼足夠爬取很多網站,如果涉及到不容易爬取的網站,那可能需要破解加密算法或者抓包等等,不用著急,一步一步完善!

結語

我們是‘廣州銷商科技有限公司(沿線整租)’數據分析部,歡迎大家關注我們,多謝!


分享到:


相關文章: