导航:首页 > 编程语言 > python多线程爬取

python多线程爬取

发布时间:2022-12-30 11:39:32

1. python 多线程爬取网站数据利用线程池

"""

@author: wangxingchun

多线程(线程池)

下载数据

"""

import requests

import csv

from concurrent.futures import ThreadPoolExecutor as tp

#创建一个csv文件,注意创建writer对象"csv.writer()"

f = open('xinfadi.csv','w',encoding='utf8')

csvwrite = csv.writer(f)

#如果写入txt文件,不需要创建writer对象。

# f = open('xinfadidata.txt','w',encoding='utf8')

#创建一个函数,以页码做为参数

def down(n_page):

url = 'http://www.xinfadi.com.cn/getPriceData.html'

data = {'count': 428225,'current': n_page,'limit': 20}

resp = requests.post(url,data=data)

datas =resp.json()

#通过分析数据嵌套情况,获取数据。此处可在网页开发工具json数据中查看分析。

for i in range(len(datas['list'])):

name = datas['list'][i]['prodName']

highPrice = datas['list'][i]['highPrice']

lowPrice = datas['list'][i]['lowPrice']

pubDate = datas['list'][i]['pubDate']

place = datas['list'][i]['place']

csvwrite.writerow((name,highPrice,lowPrice,pubDate,place))#writerow要求写入的是可迭代对象

# f.writelines(f'{name},{highPrice},{lowPrice},{pubDate},{place} ')

resp.close()

if __name__ == '__main__':

with tp(50) as t: #创建线程池,

for n in range(1,101): #遍历数据网页

t.submit(down,n) #提交给线程池,进行多线程下载

print(f'共{n}页数据下载完毕!')

f.close()

2. 有没有易懂的 Python 多线程爬虫代码

Python 在程序并行化方面多少有些声名狼藉。撇开技术上的问题,例如线程的实现和 GIL1,我觉得错误的教学指导才是主要问题。常见的经典 Python 多线程、多进程教程多显得偏“重”。而且往往隔靴搔痒,没有深入探讨日常工作中最有用的内容。
传统的例子
简单搜索下“Python 多线程教程”,不难发现几乎所有的教程都给出涉及类和队列的例子:
#Example.py
'''
Standard Procer/Consumer Threading Pattern
'''

import time
import threading
import Queue

class Consumer(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self._queue = queue

def run(self):
while True:
# queue.get() blocks the current thread until
# an item is retrieved.
msg = self._queue.get()
# Checks if the current message is
# the "Poison Pill"
if isinstance(msg, str) and msg == 'quit':
# if so, exists the loop
break
# "Processes" (or in our case, prints) the queue item
print "I'm a thread, and I received %s!!" % msg
# Always be friendly!
print 'Bye byes!'

def Procer():
# Queue is used to share items between
# the threads.
queue = Queue.Queue()

# Create an instance of the worker
worker = Consumer(queue)
# start calls the internal run() method to
# kick off the thread
worker.start()

# variable to keep track of when we started
start_time = time.time()
# While under 5 seconds..
while time.time() - start_time < 5:
# "Proce" a piece of work and stick it in
# the queue for the Consumer to process
queue.put('something at %s' % time.time())
# Sleep a bit just to avoid an absurd number of messages
time.sleep(1)

# This the "poison pill" method of killing a thread.
queue.put('quit')
# wait for the thread to close down
worker.join()

if __name__ == '__main__':
Procer()

哈,看起来有些像 Java 不是吗?
我并不是说使用生产者/消费者模型处理多线程/多进程任务是错误的(事实上,这一模型自有其用武之地)。只是,处理日常脚本任务时我们可以使用更有效率的模型。
问题在于…
首先,你需要一个样板类;
其次,你需要一个队列来传递对象;
而且,你还需要在通道两端都构建相应的方法来协助其工作(如果需想要进行双向通信或是保存结果还需要再引入一个队列)。
worker 越多,问题越多
按照这一思路,你现在需要一个 worker 线程的线程池。下面是一篇 IBM 经典教程中的例子——在进行网页检索时通过多线程进行加速。
#Example2.py
'''
A more realistic thread pool example
'''

import time
import threading
import Queue
import urllib2

class Consumer(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self._queue = queue

def run(self):
while True:
content = self._queue.get()
if isinstance(content, str) and content == 'quit':
break
response = urllib2.urlopen(content)
print 'Bye byes!'

def Procer():
urls = [
'', ''
'', ''
# etc..
]
queue = Queue.Queue()
worker_threads = build_worker_pool(queue, 4)
start_time = time.time()

# Add the urls to process
for url in urls:
queue.put(url)
# Add the poison pillv
for worker in worker_threads:
queue.put('quit')
for worker in worker_threads:
worker.join()

print 'Done! Time taken: {}'.format(time.time() - start_time)

def build_worker_pool(queue, size):
workers = []
for _ in range(size):
worker = Consumer(queue)
worker.start()
workers.append(worker)
return workers

if __name__ == '__main__':
Procer()

这段代码能正确的运行,但仔细看看我们需要做些什么:构造不同的方法、追踪一系列的线程,还有为了解决恼人的死锁问题,我们需要进行一系列的 join 操作。这还只是开始……
至此我们回顾了经典的多线程教程,多少有些空洞不是吗?样板化而且易出错,这样事倍功半的风格显然不那么适合日常使用,好在我们还有更好的方法。
何不试试 map
map 这一小巧精致的函数是简捷实现 Python 程序并行化的关键。map 源于 Lisp 这类函数式编程语言。它可以通过一个序列实现两个函数之间的映射。
urls = ['', '']
results = map(urllib2.urlopen, urls)

上面的这两行代码将 urls 这一序列中的每个元素作为参数传递到 urlopen 方法中,并将所有结果保存到 results 这一列表中。其结果大致相当于:
results = []
for url in urls:
results.append(urllib2.urlopen(url))

map 函数一手包办了序列操作、参数传递和结果保存等一系列的操作。
为什么这很重要呢?这是因为借助正确的库,map 可以轻松实现并行化操作。

在 Python 中有个两个库包含了 map 函数: multiprocessing 和它鲜为人知的子库 multiprocessing.mmy.
这里多扯两句: multiprocessing.mmy? mltiprocessing 库的线程版克隆?这是虾米?即便在 multiprocessing 库的官方文档里关于这一子库也只有一句相关描述。而这句描述译成人话基本就是说:"嘛,有这么个东西,你知道就成."相信我,这个库被严重低估了!
mmy 是 multiprocessing 模块的完整克隆,唯一的不同在于 multiprocessing 作用于进程,而 mmy 模块作用于线程(因此也包括了 Python 所有常见的多线程限制)。
所以替换使用这两个库异常容易。你可以针对 IO 密集型任务和 CPU 密集型任务来选择不同的库。2
动手尝试
使用下面的两行代码来引用包含并行化 map 函数的库:
from multiprocessing import Pool
from multiprocessing.mmy import Pool as ThreadPool

实例化 Pool 对象:
pool = ThreadPool()

这条简单的语句替代了 example2.py 中 build_worker_pool 函数 7 行代码的工作。它生成了一系列的 worker 线程并完成初始化工作、将它们储存在变量中以方便访问。
Pool 对象有一些参数,这里我所需要关注的只是它的第一个参数:processes. 这一参数用于设定线程池中的线程数。其默认值为当前机器 CPU 的核数。
一般来说,执行 CPU 密集型任务时,调用越多的核速度就越快。但是当处理网络密集型任务时,事情有有些难以预计了,通过实验来确定线程池的大小才是明智的。
pool = ThreadPool(4) # Sets the pool size to 4

线程数过多时,切换线程所消耗的时间甚至会超过实际工作时间。对于不同的工作,通过尝试来找到线程池大小的最优值是个不错的主意。
创建好 Pool 对象后,并行化的程序便呼之欲出了。我们来看看改写后的 example2.py
import urllib2
from multiprocessing.mmy import Pool as ThreadPool

urls = [

# etc..
]

# Make the Pool of workers
pool = ThreadPool(4)
# Open the urls in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)
#close the pool and wait for the work to finish
pool.close()
pool.join()

实际起作用的代码只有 4 行,其中只有一行是关键的。map 函数轻而易举的取代了前文中超过 40 行的例子。为了更有趣一些,我统计了不同方法、不同线程池大小的耗时情况。
# results = []
# for url in urls:
# result = urllib2.urlopen(url)
# results.append(result)

# # ------- VERSUS ------- #

# # ------- 4 Pool ------- #
# pool = ThreadPool(4)
# results = pool.map(urllib2.urlopen, urls)

# # ------- 8 Pool ------- #

# pool = ThreadPool(8)
# results = pool.map(urllib2.urlopen, urls)

# # ------- 13 Pool ------- #

# pool = ThreadPool(13)
# results = pool.map(urllib2.urlopen, urls)

结果:
# Single thread: 14.4 Seconds
# 4 Pool: 3.1 Seconds
# 8 Pool: 1.4 Seconds
# 13 Pool: 1.3 Seconds

很棒的结果不是吗?这一结果也说明了为什么要通过实验来确定线程池的大小。在我的机器上当线程池大小大于 9 带来的收益就十分有限了。
另一个真实的例子
生成上千张图片的缩略图
这是一个 CPU 密集型的任务,并且十分适合进行并行化。
基础单进程版本
import os
import PIL

from multiprocessing import Pool
from PIL import Image

SIZE = (75,75)
SAVE_DIRECTORY = 'thumbs'

def get_image_paths(folder):
return (os.path.join(folder, f)
for f in os.listdir(folder)
if 'jpeg' in f)

def create_thumbnail(filename):
im = Image.open(filename)
im.thumbnail(SIZE, Image.ANTIALIAS)
base, fname = os.path.split(filename)
save_path = os.path.join(base, SAVE_DIRECTORY, fname)
im.save(save_path)

if __name__ == '__main__':
folder = os.path.abspath(
'11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840')
os.mkdir(os.path.join(folder, SAVE_DIRECTORY))

images = get_image_paths(folder)

for image in images:
create_thumbnail(Image)

上边这段代码的主要工作就是将遍历传入的文件夹中的图片文件,一一生成缩略图,并将这些缩略图保存到特定文件夹中。
这我的机器上,用这一程序处理 6000 张图片需要花费 27.9 秒。
如果我们使用 map 函数来代替 for 循环:
import os
import PIL

from multiprocessing import Pool
from PIL import Image

SIZE = (75,75)
SAVE_DIRECTORY = 'thumbs'

def get_image_paths(folder):
return (os.path.join(folder, f)
for f in os.listdir(folder)
if 'jpeg' in f)

def create_thumbnail(filename):
im = Image.open(filename)
im.thumbnail(SIZE, Image.ANTIALIAS)
base, fname = os.path.split(filename)
save_path = os.path.join(base, SAVE_DIRECTORY, fname)
im.save(save_path)

if __name__ == '__main__':
folder = os.path.abspath(
'11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840')
os.mkdir(os.path.join(folder, SAVE_DIRECTORY))

images = get_image_paths(folder)

pool = Pool()
pool.map(creat_thumbnail, images)
pool.close()
pool.join()

5.6 秒!
虽然只改动了几行代码,我们却明显提高了程序的执行速度。在生产环境中,我们可以为 CPU 密集型任务和 IO 密集型任务分别选择多进程和多线程库来进一步提高执行速度——这也是解决死锁问题的良方。此外,由于 map 函数并不支持手动线程管理,反而使得相关的 debug 工作也变得异常简单。
到这里,我们就实现了(基本)通过一行 Python 实现并行化。

3. 如何用Python爬取数据

方法/步骤

4. python之多线程

进程的概念:以一个整体的形式暴露给操作系统管理,里面包含各种资源的调用。 对各种资源管理的集合就可以称为进程。
线程的概念:是操作系统能够进行运算调度的最小单位。本质上就是一串指令的集合。

进程和线程的区别:
1、线程共享内存空间,进程有独立的内存空间。
2、线程启动速度快,进程启动速度慢。注意:二者的运行速度是无法比较的。
3、线程是执行的指令集,进程是资源的集合
4、两个子进程之间数据不共享,完全独立。同一个进程下的线程共享同一份数据。
5、创建新的线程很简单,创建新的进程需要对他的父进程进行一次克隆。
6、一个线程可以操作(控制)同一进程里的其他线程,但是进程只能操作子进程
7、同一个进程的线程可以直接交流,两个进程想要通信,必须通过一个中间代理来实现。
8、对于线程的修改,可能会影响到其他线程的行为。但是对于父进程的修改不会影响到子进程。

第一个程序,使用循环来创建线程,但是这个程序中一共有51个线程,我们创建了50个线程,但是还有一个程序本身的线程,是主线程。这51个线程是并行的。注意:这个程序中是主线程启动了子线程。

相比上个程序,这个程序多了一步计算时间,但是我们观察结果会发现,程序显示的执行时间只有0.007秒,这是因为最后一个print函数它存在于主线程,而整个程序主线程和所有子线程是并行的,那么可想而知,在子线程还没有执行完毕的时候print函数就已经执行了,总的来说,这个时间只是执行了一个线程也就是主线程所用的时间。

接下来这个程序,吸取了上面这个程序的缺点,创建了一个列表,把所有的线程实例都存进去,然后使用一个for循环依次对线程实例调用join方法,这样就可以使得主线程等待所创建的所有子线程执行完毕才能往下走。 注意实验结果:和两个线程的结果都是两秒多一点

注意观察实验结果,并没有执行打印task has done,并且程序执行时间极其短。
这是因为在主线程启动子线程前把子线程设置为守护线程。
只要主线程执行完毕,不管子线程是否执行完毕,就结束。但是会等待非守护线程执行完毕
主线程退出,守护线程全部强制退出。皇帝死了,仆人也跟着殉葬
应用的场景 : socket-server

注意:gil只是为了减低程序开发复杂度。但是在2.几的版本上,需要加用户态的锁(gil的缺陷)而在3点几的版本上,加锁不加锁都一样。

下面这个程序是一个典型的生产者消费者模型。
生产者消费者模型是经典的在开发架构中使用的模型
运维中的集群就是生产者消费者模型,生活中很多都是

那么,多线程的使用场景是什么?
python中的多线程实质上是对上下文的不断切换,可以说是假的多线程。而我们知道,io操作不占用cpu,计算占用cpu,那么python的多线程适合io操作密集的任务,比如socket-server,那么cpu密集型的任务,python怎么处理?python可以折中的利用计算机的多核:启动八个进程,每个进程有一个线程。这样就可以利用多进程解决多核问题。

5. Python爬虫实战,Python多线程抓取5千多部最新电影下载链接


利用Python多线程爬了5000多部最新电影下载链接,废话不多说~

让我们愉快地开始吧~

Python版本: 3.6.4

相关模块:

requests模块;

re模块;

csv模块;

以及一些Python自带的模块。

安装Python并添加到环境变量,pip安装需要的相关模块即可。

拿到链接之后,接下来就是继续访问这些链接,然后拿到电影的下载链接

但是这里还是有很多的小细节,例如我们需要拿到电影的总页数,其次这么多的页面,一个线程不知道要跑到什么时候,所以我们首先先拿到总页码,然后用多线程来进行任务的分配

我们首先先拿到总页码,然后用多线程来进行任务的分配

总页数其实我们用re正则来获取

爬取的内容存取到csv,也可以写个函数来存取

开启4个进程来下载链接

您学废了吗?最后祝大家天天进步!!学习Python最重要的就是心态。我们在学习过程中必然会遇到很多难题,可能自己想破脑袋都无法解决。这都是正常的,千万别急着否定自己,怀疑自己。如果大家在刚开始学习中遇到困难,想找一个python学习交流环境,可以加入我们,领取学习资料,一起讨论,会节约很多时间,减少很多遇到的难题。

6. python爬虫如何分析一个将要爬取的网站

首先,你去爬取一个网站,

你会清楚这个网站是属于什么类型的网站(新闻,论坛,贴吧等等)。

你会清楚你需要哪部分的数据

你需要去想需要的数据你将如何编写表达式去解析。

你会碰到各种反爬措施,无非就是各种网络各种解决。当爬取成本高于数据成本,你会选择放弃。

你会利用你所学各种语言去解决你将要碰到的问题,利用各种语言的client组件去请求你想要爬取的URL,获取到HTML,利用正则,XPATH去解析你想要的数据,然后利用sql存储各类数据库。

7. python可以多线程爬虫吗

当然可以,比如python的爬虫框架scrapy就提供了多线程的功能,当然你也可以自己写多线程

8. python3 获取title的编写

水平有限,不会造轮子,只为学习。

在原来写端口扫描的基础上进一步爬取web服务的title信息,方便收集信息。
适用于在外网收集资产形成IP字典后去批量获取title,意在最快地寻找脆弱点。
自行安装BeautifulSoup4、requests库。
V1.0
python3 写的单线程爬取web系统的title信息。
注解
1.使用BeautifulSoup4库来解析HTML,爬取title信息;
2.打印title时,带有颜色的输出;
3.在开放443、4433、8443端口时,采用https进行访问;
4.解决SSL认证问题;

V1.0.1
python3 单线程写的爬取网站title信息。增加了OptionParser模块,运行时看起来比较舒服。
注解
1.依然是从IP字典里爬取,实际运行脚本时,即使没有获取title,也应该手动访问开放的端口,往往有意外惊喜;
2.端口内置在脚本里,可自行修改;

V1.1
python3写的多线程爬取web系统的title。
注解
1.只是使用threading模块,没有添加到队列,也没有加锁;本身port_list也不多;

V1.2
python3 写的多线程加队列的来爬取web系统的title信息。
注解
1.增加了queue队列,和多线程配合使用。更加实用;

V1.3
python3 写的多线程加队列的来爬取web系统的title信息。
增加result输出结果到文本,适应于内外网端口扫描并获取title

python3 编写扫描IP网段如192.168.1.0/24某些指定应用端口爬取title信息。 在代理进行内网渗透时内网资产不容易找到。
适用于内网、外网环境。
自行安装BeautifulSoup4、requests库。
V2.0
python3写的扫描IP段并爬取title信息,收集资产。
注解
1.使用ipaddress模块获取C段地址,也可以是B段;
2.只使用threading模块,没有添加队列queue;

V2.1
python3 写的多线程扫描IP段爬取title。在一定线程下,代理探测内网资产title的非常使用。
注解
1.port_list列表移动到scan方法里;
2.将IP添加到queue队列,而不是端口;

V2.2
python3 写的多线程扫描IP段爬取title。
注解
1.只是增加了result_out方法,将结果输出到指定文件;

https://github.com/aedoo/WebServiceScanner/blob/master/webservicescanner.py

9. python 怎么实现多线程的

线程也就是轻量级的进程,多线程允许一次执行多个线程,Python是多线程语言,它有一个多线程包,GIL也就是全局解释器锁,以确保一次执行单个线程,一个线程保存GIL并在将其传递给下一个线程之前执行一些操作,也就产生了并行执行的错觉。

10. python如何才能获取src地址

Copyright © 1999-2020, CSDN.NET, All Rights Reserved

python
打开APP

pergoods
关注
Python多线程爬取网站image的src属性实例 原创
2017-05-16 11:18:51

pergoods

码龄6年

关注
# coding=utf-8
'''
Created on 2017年5月16日
@author: chenkai
Python多线程爬取某单无聊图图片地址(requests+BeautifulSoup+threading+Queue模块)
'''

import requests
from bs4 import BeautifulSoup
import threading
import Queue
import time

class Spider_Test(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.__queue = queue
def run(self):
while not self.__queue.empty():
page_url=self.__queue.get() [color=red]#从队列中取出url[/color]
print page_url
self.spider(page_url)
def spider(self,url):
r=requests.get(url) [color=red]#请求url[/color]
soup=BeautifulSoup(r.content,'lxml') [color=red]#r.content就是响应内容,转换为lxml的bs对象[/color]
imgs = soup.find_all(name='img',attrs={}) #查找所有的img标签,并获取标签属性值(为列表类型)
for img in imgs:
if 'onload' in str(img): [color=red]#img属性集合中包含onload属性的为动态图.gif,[/color]
print 'http:'+img['org_src']
else:
print 'http:'+img['src']

def main():
queue=Queue.Queue()
url_start = 'http://jandan.net/pic/page-'
for i in range(293,295):
url = url_start+str(i)+'#comment'
queue.put(url) [color=red]#将循环拼接的url放入队列中[/color]

threads=[]
thread_count=2 [color=red]#默认线程数(可自动修改)[/color]
for i in range(thread_count):
threads.append(Spider_Test(queue))
for i in threads:
i.start()
for i in threads:
i.join()

if __name__ == '__main__':[color=red] #在.py文件中使用这个条件语句,可以使这个条件语句块中的命令只在它独立运行时才执行[/color]
time_start = time.time()
main() [color=red]#调用main方法[/color]
print time.time()-time_start

[color=red]#背景知识[/color]
'''
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。
将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。
将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。

'''

[color=red]如果想要下载图片需要
import urllib

再替换spider方法即可[/color]

def spider(self,url):
r=requests.get(url)
soup=BeautifulSoup(r.content,'lxml')
imgs = soup.find_all(name='img',attrs={})
urls=[]
for img in imgs:
if 'onload' in str(img):
print 'http:'+img['org_src']
urls.append('http:'+img['org_src'])
else:
print 'http:'+img['src']
url = urls.append('http:'+img['src'])
#下载图片
k=0
for urlitem in urls:
k+=1
if '.jpg' in urlitem:
urllib.urlretrieve(url=urlitem,filename='F:\image\\'+str(k)+'.jpg')

[color=red]-----------多线程访问网络实例[/color]
#coding:utf-8
import requests
import threading
import time
import sys

url = 'https://www..com'

def get_():
global url
time_start = time.time()
r = requests.get(url=url)
times = time.time()-time_start
sys.stdout.write('status:%s time:%s current_time:%s\n'%(r.status_code,times,time.strftime('%H:%M:%S')))

def main():
threads = []
thread_count = 10
for i in range(thread_count):
t = threading.Thread(target=get_,args=())
threads.append(t)
for i in range(thread_count):
threads[i].start()

for i in range(thread_count):
threads[i].join()

if __name__=='__main__':

阅读全文

与python多线程爬取相关的资料

热点内容
dvd光盘存储汉子算法 浏览:757
苹果邮件无法连接服务器地址 浏览:962
phpffmpeg转码 浏览:671
长沙好玩的解压项目 浏览:144
专属学情分析报告是什么app 浏览:564
php工程部署 浏览:833
android全屏透明 浏览:736
阿里云服务器已开通怎么办 浏览:803
光遇为什么登录时服务器已满 浏览:302
PDF分析 浏览:484
h3c光纤全工半全工设置命令 浏览:143
公司法pdf下载 浏览:381
linuxmarkdown 浏览:350
华为手机怎么多选文件夹 浏览:683
如何取消命令方块指令 浏览:349
风翼app为什么进不去了 浏览:778
im4java压缩图片 浏览:362
数据查询网站源码 浏览:150
伊克塞尔文档怎么进行加密 浏览:892
app转账是什么 浏览:163