编写多线程爬虫(线程数量4个)爬取豆瓣网站人文标签下 所有书籍(至少爬取前10页)的信息(包括书名、作者、出版社、出版 日期、页数、价格、ISBN号、豆瓣评分、评价人数、书籍封面、 URL),并按照豆瓣评分降序保存(以标签名称命名)
时间: 2023-09-08 21:10:54 浏览: 120
好的,这个问题需要涉及到多线程编程和网络爬虫技术。我会尽可能详细地解答。首先,我们需要使用Python语言来实现这个爬虫程序。
1. 导入需要的模块
我们需要使用到 requests、BeautifulSoup、os、re、time和threading等模块。requests用于发送HTTP请求,BeautifulSoup用于解析HTML页面,os用于创建目录,re用于正则表达式匹配,time用于设置访问时间间隔,threading用于实现多线程。
先贴上代码:
```python
import requests
from bs4 import BeautifulSoup
import os
import re
import time
import threading
```
2. 定义函数
我们需要定义多个函数来实现这个爬虫程序。首先是获取页面内容的函数:
```python
def get_page(url):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
r = requests.get(url, headers=headers)
r.raise_for_status()
r.encoding = 'utf-8'
return r.text
except:
return ''
```
这个函数使用requests库发送HTTP请求,获取页面的HTML内容。如果请求失败,返回空字符串。
接下来是获取书籍信息的函数:
```python
def get_book_info(book_url):
book_info = {}
html = get_page(book_url)
soup = BeautifulSoup(html, 'html.parser')
info = soup.find('div', {'id': 'info'})
title = soup.find('span', {'property': 'v:itemreviewed'}).get_text()
book_info['书名'] = title
author = info.find_all('a', href=re.compile('https://book.douban.com/author/\\d+/$'))
author_name = ''
for a in author:
author_name += a.get_text() + '/'
book_info['作者'] = author_name[:-1]
publisher = info.find(text=re.compile('出版社:')).next_sibling.strip()
book_info['出版社'] = publisher
pubdate = info.find(text=re.compile('出版年:')).next_sibling.strip()
book_info['出版日期'] = pubdate
pages = info.find(text=re.compile('页数:')).next_sibling.strip()
book_info['页数'] = pages
price = info.find(text=re.compile('定价:')).next_sibling.strip()
book_info['价格'] = price
isbn = info.find(text=re.compile('ISBN:')).next_sibling.strip()
book_info['ISBN号'] = isbn
rating = soup.find('strong', {'class': 'rating_num'}).get_text()
book_info['豆瓣评分'] = rating
comment_count = soup.find('span', {'property': 'v:votes'}).get_text()
book_info['评价人数'] = comment_count
cover = soup.find('a', {'class': 'nbg'}).find('img')['src']
book_info['书籍封面'] = cover
return book_info
```
这个函数传入一个书籍的URL,解析HTML页面,获取书籍的相关信息,并将其存储到一个字典中,最后返回字典。
3. 实现爬虫程序
我们需要定义一个爬虫类,其中包含了多线程爬虫的主要逻辑。
```python
class DoubanSpider:
def __init__(self, tag_name, thread_num=4):
self.tag_name = tag_name
self.thread_num = thread_num
self.page_num = 10
self.book_infos = []
self.lock = threading.Lock()
self.semaphore = threading.Semaphore(thread_num)
def run(self):
if not os.path.exists(self.tag_name):
os.mkdir(self.tag_name)
for i in range(self.page_num):
url = f'https://book.douban.com/tag/{self.tag_name}?start={i * 20}&type=T'
html = get_page(url)
soup = BeautifulSoup(html, 'html.parser')
book_list = soup.find_all('li', {'class': 'subject-item'})
for book in book_list:
book_url = book.find('a', {'class': 'nbg'})['href']
self.semaphore.acquire()
t = threading.Thread(target=self.get_book_info, args=(book_url,))
t.start()
for t in threading.enumerate():
if t != threading.current_thread():
t.join()
self.book_infos.sort(key=lambda x: float(x['豆瓣评分']), reverse=True)
with open(f'{self.tag_name}/{self.tag_name}.txt', 'w', encoding='utf-8') as f:
for book in self.book_infos:
f.write(f"书名:{book['书名']}\n")
f.write(f"作者:{book['作者']}\n")
f.write(f"出版社:{book['出版社']}\n")
f.write(f"出版日期:{book['出版日期']}\n")
f.write(f"页数:{book['页数']}\n")
f.write(f"价格:{book['价格']}\n")
f.write(f"ISBN号:{book['ISBN号']}\n")
f.write(f"豆瓣评分:{book['豆瓣评分']}\n")
f.write(f"评价人数:{book['评价人数']}\n")
f.write(f"书籍封面:{book['书籍封面']}\n")
f.write(f"URL:{book['URL']}\n\n")
def get_book_info(self, book_url):
book_info = get_book_info(book_url)
with self.lock:
self.book_infos.append(book_info)
self.semaphore.release()
```
这个类的构造函数中传入标签名称和线程数量两个参数。run方法首先创建一个目录来存储爬取的数据,然后循环爬取前10页的书籍列表。对于每一页中的每一本书,我们创建一个线程来获取书籍信息,同时使用一个Semaphore对象来限制线程数量。获取书籍信息的函数中,我们使用一个Lock对象来保证线程安全,将获取到的书籍信息存储到一个列表中。当所有线程执行完毕后,我们按照豆瓣评分对书籍信息进行排序,最后将其写入到一个文本文件中。
4. 测试
我们可以通过创建一个DoubanSpider对象,传入标签名称和线程数量来启动爬虫程序。比如:
```python
spider = DoubanSpider('人文', thread_num=4)
spider.run()
```
这个程序会在当前目录下创建一个名为“人文”的目录,并在其中写入爬取到的数据。
由于涉及到网络爬虫,建议在合理范围内使用,避免对网站造成过大的负担。
阅读全文