目标网站:https://www.1ppt.com/moban/
需求:
1、用多线程爬取前10页模板名字和模板详情页链接
2、把模板名字和模板详情页链接保存到模板.csv文件里面
import requests
from lxml import etree
import time
from queue import Queue
import threading
import csv
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'}
class Product(threading.Thread): # 生产者
# 在自定义类中写了init方法 调用父类Thread的init方法
def __init__(self, page_url, img_url):
super().__init__()
# 初始化方法 将url拿到
self.page_url = page_url
self.img_url = img_url
pass
def run(self):
# 让生产者拿到url去处理
# 三个生产者 怎么去处理10个url?让生产者一直工作 直到队列为空(队列里的url处理完了)
while True:
# 如果队列为空 结束循环
if self.page_url.empty():
break
else:
# 如果队列不为空 拿到url去获取数据
url = self.page_url.get()
# 对url发生请求 进行解析 单独写一个解析数据的方法
self.parse_data(url)
# 解析数据
def parse_data(self, url):
resposne = requests.get(url, headers=headers)
resposne.encoding = 'gb2312'
data = resposne.text
time.sleep(2)
# 创建对象
html = etree.HTML(data)
a_tag = html.xpath('//ul[@class="tplist"]/li/h2/a')
# print('检查', len(img_tag))
for a in a_tag:
href = a.xpath('./@href')
name = a.xpath('./text()')
self.img_url.put((href, name))
class Customer(threading.Thread):
count = 1
def __init__(self,img_url):
super().__init__()
self.img_url = img_url
def run(self):
while True:
if self.img_url.empty():
break
else:
img_data = self.img_url.get()
url, name = img_data
if __name__ == '__main__':
page_url = Queue()
for i in range(1, 11):
url = f'https://www.1ppt.com/moban/ppt_moban_{i}.html'
page_url.put(url)
img_url = Queue()
t_lst = []
for i in range(10):
t = Product(page_url, img_url)
t.start()
t_lst.append(t)
for i in t_lst:
i.join()
for i in range(10):
t1 = Customer(img_url)
t1.start()
import requests
from lxml import etree
from queue import Queue
import threading
from urllib.parse import urljoin
import pandas as pd
import time
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
'Refer': 'https://www.1ppt.com/moban/ppt_moban_1.html',
'Host': 'www.1ppt.com'
}
class Product(threading.Thread): # 生产者
# 在自定义类中写了init方法 调用父类Thread的init方法
def __init__(self, page_url, img_url):
super().__init__()
# 初始化方法 将url拿到
self.page_url = page_url
self.img_url = img_url
pass
def run(self):
# 让生产者拿到url去处理
# 三个生产者 怎么去处理10个url?让生产者一直工作 直到队列为空(队列里的url处理完了)
while True:
# 如果队列为空 结束循环
if self.page_url.empty():
break
else:
# 如果队列不为空 拿到url去获取数据
url = self.page_url.get()
# 对url发生请求 进行解析 单独写一个解析数据的方法
self.parse_data(url)
# 解析数据
def parse_data(self, url):
resposne = requests.get(url, headers=headers)
resposne.encoding = 'gb2312'
data = resposne.text
time.sleep(2)
# 创建对象
html = etree.HTML(data)
a_tag = html.xpath('//ul[@class="tplist"]/li/h2/a')
# print('检查', len(img_tag))
for a in a_tag:
href = urljoin('https://www.1ppt.com/moban/ppt_moban_1.html',a.xpath('./@href')[0].strip())
name = a.xpath('./text()')[0].strip()
self.img_url.put((href, name))
class Customer(object):
def __init__(self, img_url,filename):
super().__init__()
self.img_url = img_url
self.filename = filename
self.ppt_module_list = []
def _get_data(self):
while True:
if self.img_url.empty():
break
else:
img_data = self.img_url.get()
url, name = img_data
self.ppt_module_list.append( [name,url] )
def run(self):
self._get_data()
pd.DataFrame(self.ppt_module_list,columns=['名称','URL地址']).to_csv(self.filename,index=False)
if __name__ == '__main__':
page_url = Queue()
for i in range(1, 11):
url = f'https://www.1ppt.com/moban/ppt_moban_{i}.html'
page_url.put(url)
img_url = Queue()
t_lst = []
for i in range(10):
t = Product(page_url, img_url)
t.start()
t_lst.append(t)
for i in t_lst:
i.join()
t1 = Customer(img_url,'data.csv')
t1.run()
完善的地方(纯属个人观点):
① headers 请求头添加 Refer 字段,防止IP被封
② 生产者的类中 href 我用到了 urljoin 方法
③ 消费者了类我把多线程去掉了
④ 消费者类用了pandas模块(个人习惯用这个模块),直接把把数据写入到csv文件中
效果展示:
仔细调试哦,问题所在需要细心观察
报错了,报什么错?
把报错信息贴出来,不要让别人猜
虽然代码贴出来了,但还是建议附个报错截图
代码没什么问题,你没有写写入csv程序。在parse_data函数里面,解析出结果后就可以写入了(我加了一句print()的那个位置)。
如果报错无法导入requests、lxml包的话,使用pip install requests安装一下就行了。