1.什么是程序、进程和线程。
程序:一个应用可以当做一个程序,比如qq软件
进程:程序运行最小的资源分配单位。一个程序可以有多个进程。
线程:cpu最小的调度单位,必须依赖进程而存在。线程没有独立的资源,所有线程共享他所在进程的资源。
他们之间的关系:一个程序至少有一个进程,一个进程至少有一个线程。
2.多线程:多线程是指一个程序包含多个并行的线程来完成不同的任务。
多线程的优点:可以提高cpu的利用率。
3、创建多线程的第一种方法:
(1)导包
import threading
(2)创建一个线程
t = threading.Thread(
target= 方法名,
args=(,)#方法的参数
)
(3)启动线程
t.start()
4、线程生命周期:但我们启动一个线程到这个线程的任务方法执行完毕的过程就是这个线程生命周期。
5、查看线程数量:threading.enumerate()—可以查看当前进程下的线程的数量。
6、创建线程的第二种方法:通过线程类来创建。
步骤如下:
(1)继承threading.Thread
(2)重写run方法。
(3)实例化这个类就可以创建线程,之后在调用start()方法启动就可以了。
7.线程类传参:必须在线程类的init方法中调用父类的init方法。
调用父类的init方法有两种:
super().init()
threading.Thread.init(self)
python编译器:
cpython --c语言写的
jpython
pypython
8.线程类中,我们可以通过实例化线程类的时候,通过指定name这个参数来给线程起名字:
t = MyThread(name= “downloadThread”)
t.start()
在线程类中调用self.name来使用线程的名称。
如果不指定名称,默认情况下就是Thread-1,Thread-2,……
补充:格式化字符串的三种方法:
(1)’…%s.’ %i
(2)‘。{3}。。。{2}。。{1}’.format(a,b,c)
‘。{}。。。{}。。{}’.format(a,b,c)
(3)f’…{filename}…’
9线程的执行顺序:线程执行顺序是不固定,原因主要是由线程状态决定。
线程的五中状态:
(1)新建:线程创建
t = Mythread(i)或者使用t = threading.Thread(target=)
(2)就绪:当启动线程后,线程就进入就绪状态,就绪状态的线程会被放到一个cpu的调度队列里面,cpu会负责让其中的线程运行,变为运行状态。
(3)运行状态:cpu调度一个就绪状态的线程,该线程就变为运行状态。
(4)阻塞状态:当运行状态的线程被阻塞time.sleep()就变为阻塞状态,阻塞状态的线程会重新变为就绪状态才能继续运行。
(5)死亡状态:线程执行完毕。
10.多个线程对公有变量处理时,容易造成数据的混乱,造成线程不安全问题。
11.多线程和多进程
(1)多线程的优点:
程序逻辑和控制方式复杂;
所有线程可以直接共享内存和变量;
线程方式消耗的总资源比进程方式好。
(2)多线程缺点:
每个线程与主程序共用地址空间,受限于2GB地址空间;
线程之间的同步和加锁控制比较麻烦;
一个线程的崩溃可能影响到整个程序的稳定性;
(3)多进程优点:
每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;
通过增加CPU,就可以容易扩充性能;
每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大 。
(4) 多进程缺点:
逻辑控制复杂,需要和主程序交互;
需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算 多进程调度开销比较大。
在实际开发中,选择多线程和多进程应该从具体实际开发来进行选择。最好是多进程和多线程结合,即根据实际的需要,每个CPU开启一个子进程,这个子进程开启多线程可以为若干同类型的数据进行处理。
12.通过互斥锁来确保线程之间数据的正确。
创建互斥锁的步骤:
1.创建锁对象
mutex = threading.Lock()
2.
if mutex.acpuire():
'''
对公有变量处理的代码
'''
mutex.release()#释放锁
13.死锁
产生死锁的情况有两种:
1.当一个线程获取了锁之后,还未释放的前提下,试图获取另一把锁,此时会产生死锁。
2.线程A获取锁1,线程B获取了锁2,线程A还未释放锁1继续想要获取锁2,线程B也未释放锁2,同时想要获取锁1
14.爬取网站的流程:
1、确定网站哪个url是数据的来源。
2.简要分析一下网站结构,查看数据一般放在哪里。
3.查看是否有分页,解决分页的问题。
4.发送请求,查看response.text里面是否有我们想要的数据内容。
5.如果有数据,就用相应的提取数据的方法提取数据保存。
6.如果没有,我们就可以通过以下两种方法来实现爬取:
(1)分析数据来源,查看是否通过一些接口获取到的页面数据。(首推)
如果没有在页面中返回数据,我们应该首先想到,数据有可能是从ajax接口中获取的。
分析接口的步骤:
1.查看该接口返回的数据是否使我们想要的。
2.重点查看该接口的请求参数。
了解哪些请求参数是变化的以及他的变化规律。
(2)selenium+phantomjs来获取页面内容。
作业:爬取链家二手房信息。
要求:
1.爬取的字段:
名称
房间规模、
价格
建设时间
朝向
详情页链接
2.写三个文件:
1.简单py
2.面向对象
3.改成多线程
import time
from queue import Queue
import requests
from lxml import etree
from selenium import webdriver
from threading import Thread
class House(Thread):
def __init__(self,url,q):
super().__init__()
self.url = url
self.q = q
self.result = {}
self.headers = {
# 'Sec-Fetch-Mode': 'navigate',
# 'Sec-Fetch-Site': 'none',
# 'Sec-Fetch-User': '?1',
# 'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36'}
self.get_msg()
def run(self):
while not self.q.empty():
self.get_msg()
with open('result/fang.txt','w',encoding='utf-8') as fp:
fp.write(self.result)
def get_page(self,url):
response = requests.get(url, headers=self.headers).text
# print(response)
xpath_ele = etree.HTML(response)
return xpath_ele
def get_msg(self):
# for i in range(1,101):
url = self.url % self.q.get()
response = requests.get(url,headers = self.headers).text
# print(response)
xpath_ele = etree.HTML(response)
area_list = xpath_ele.xpath('//div[@data-role="ershoufang"]/div[1]/a')
# area_url_list = ['https://bj.lianjia.com/'+ele for ele in area_list]
# print(area_url_list)
for one in area_list:
page_name = one.xpath('./text()')[0]
# print(one.xpath('./@href')[0])
# print(requests.get('https://bj.lianjia.com'+one.xpath('./@href')[0],self.headers).text)
page_page = self.get_page('https://bj.lianjia.com'+one.xpath('./@href')[0])
# print(page_page)
house_list_xrl = '//div[@class="info clear"]'
house_list = page_page.xpath(house_list_xrl)
# print(house_list)
self.result[page_name] = []
for i in house_list:
# print(i)
house={}
house['name'] = i.xpath('./div[@class="title"]/a/text()')
house['url'] = i.xpath('./div[@class="title"]/a/@href')
house['price'] = i.xpath('./div[@class="priceInfo"]/div/span/text()')[0]+'万'
msg = i.xpath('./div[@class="address"]/div/text()')[0]
print(msg)
house['direction'] = msg.split('|')[2]
house['date'] = msg.split('|')[5]
house['size'] = msg.split('|')[0]
# house['direction'] = msg.split('|')[1]
self.result[page_name].append(house)
if __name__ == '__main__':
url = 'https://bj.lianjia.com/ershoufang/dongcheng/pg=%s'
# house = House(url)
# print(house.result)
st = time.time()
q = Queue()
for i in range(1,101):
q.put(i)
task_list = [House(url,q) for i in range(5)]
for task in task_list:
task.start()
for task in task_list:
task.join()
print(time.time()-st)