多线程爬虫其实很简单,只用十个线程每天即可爬取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个线程,速度肯定提高一大截,只要理解其中的原理,代码什么的就迎刃而解了;

需要源代码的私信就好,以后基本每天或者隔几天会发布一个项目实战,其实一个代码足够爬取很多网站,如果涉及到不容易爬取的网站,那可能需要破解加密算法或者抓包等等,不用着急,一步一步完善!

结语

我们是‘广州销商科技有限公司(沿线整租)’数据分析部,欢迎大家关注我们,多谢!


分享到:


相關文章: