ligxi 发表于 2020-2-7 16:02

Python爬虫练习——文泉书籍信息获取[失效]

本帖最后由 ligxi 于 2020-9-12 19:46 编辑

最近看到论坛的大佬写了很多文泉的爬虫工具,奈何本人能力有限写不出那么高级的爬虫,所以退求其次写个书籍基础信息获取的爬虫吧!

更新:
0.0.3版
新增书籍地址。

0.0.2版
1、加入Cookie是否有效的提示。
2、加入起始页,现在可以指定开始页。
3、修复小bug。

此代码会获取以下信息,有能力的可自行修改参数添加更多信息:


注意事项:
1、有些模块是第一次使用,可能存在一些bug,请见谅!
2、网站API端口可能随时会改,所以此代码可能也会随时失效。{:1_923:}
3、网站目前加强了各种防御,cookie每隔一段时间就会失效,需要重新登录获取,最后在源代码中更改"Cookie"后面的值即可。
4、在代码中加入请求的间隔时间,过快的请求很可能会被服务器拉黑一段时间。可自行修改源代码中的time.sleep()时间,单位为s,比如time.sleep(0.5)或time.sleep(2)都可以。

Cookie获取方式:
登录文泉账号后,在浏览器调出控制台,然后输入document.cookie即可获取,最后复制包括引号的所有Cookie信息。


最后送给大家一份刚获取的有关Python书籍的数据:lol
Python书籍信息:
https://www.lanzouj.com/i94zcni
源码:
https://www.lanzouj.com/i97pl9g

需要安装的第三方库:
pip install python-docx
pip install requests

代码示例:
# -*- coding: utf-8 -*-

import urllib.parse
import string
import requests
import json
import re
import time
import os
import sys

# doc文档模块
from docx import Document
from docx.shared import Inches
from docx.oxml.ns import qn

# cookie修改
Cookie = 'PHPSESSID=5s6umsm3ic7hmp9djhkia854s9; _gid=398749400617; _gidv=9e54db532452f68408485a0f3f20a1b1'
# 接收用户输入的关键字
flag = True
keyword = ''
while flag:
    keyword = input('请输入搜索的关键字:')
    if keyword:
      flag = False
    else:
      print('关键字为空,请重新输入!')

# 要发送的请求
wqxuetang_url = r'https://lib-nuanxin.wqxuetang.com/v1/search/initsearch'
# 字符转码
new_wqxuetang_url = urllib.parse.quote(wqxuetang_url, safe=string.printable)


# 发送请求
def get_response(page=1):
    # 请求头
    headers = {
      'Accept': 'application/json, text/plain, */*',
      'Accept - Encoding': 'gzip, deflate, br',
      'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
      'Connection': 'keep-alive',
      'Host': 'lib-nuanxin.wqxuetang.com',
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0',
      'Cookie': Cookie
    }
    # 要发送的数据
    data = {
      'kw': keyword,
      'type': 1,
      'begindate': '',
      'enddate': '',
      'tid': '',
      'libclass': '',
      'cnclass': '',
      'tag': '',
      'author': '',
      'pn': page,
      'size': 10,
      'isfquery': 'undefined',
      'sort': 1
    }
    # 发送请求,带数据和请求头
    response = requests.post(url=new_wqxuetang_url, data=data, headers=headers)
    # 转为JSON对象
    dict_str = json.loads(response.text)
    return dict_str


# 保存数据
def data_download(dict_str):
    global count
    # 匹配网页标签并替换
    rec = re.compile('</?+\s?\d?/?>')
    # 写入文件
    for item in dict_str['data']['list']:
      # 分割线
      data1 = '{0}【华丽的分割线】{0}\n'.format('*' * 30)
      f1.write(data1)
      # 书ID号
      data2 = '书的ID号:%s\n' % item['numid']
      f1.write(data2)
      print('BID:%s\t' % item['numid'], end='')
      # 书名
      book_name = item['name']
      result = set(re.findall(rec, book_name))
      for ret in result:
            book_name = book_name.replace(ret, '')
      data3 = '书名:《%s》\n' % book_name
      f1.write(data3)
      print('书名:《%s》\t' % book_name, end='')
      # 作者
      data4 = '作者:%s\n' % item['author']
      f1.write(data4)
      # 出版时间
      data5 = '出版时间:%s\n' % item['pubdate']
      f1.write(data5)
      print('出版时间:%s' % item['pubdate'])
      # 出版社
      data6 = '出版社:%s\n' % item['pub']
      f1.write(data6)
      # 图书简介
      des = item['descript']
      result = set(re.findall(rec, des))
      for ret in result:
            des = des.replace(ret, '')
      data7 = '图书简介 :%s\n' % des
      f1.write(data7)
      data8 = '书籍地址:https://lib-nuanxin.wqxuetang.com/#/Book/%s\n\n' % item['numid']
      f1.write(data8)
      # 刷新缓存区
      f1.flush()

      # 图片请求头
      img_headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept - Encoding': 'gzip, deflate, br',
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
            'Connection': 'keep-alive',
            'Host': 'bookask-cover.oss-cn-beijing.aliyuncs.com',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0',
            'Cookie': Cookie
      }

      # 拿到图片的请求地址
      img_url = item['coverurl']
      # 发送请求
      img_data = requests.get(url=img_url, headers=img_headers)
      # 发送间隔
      time.sleep(2)
      # 把图片写入本地目录
      img_count = '%s\\%s.jpg' % (pt, count)
      with open(img_count, 'wb') as fp:
            fp.write(img_data.content)

      # 把书籍信息写入doc
      data1 = data1.replace('\n', '')
      myDocument.add_paragraph(data1)
      # 向文档里添加图片
      myDocument.add_picture(img_count, width=Inches(2), height=Inches(3))
      # 处理文字
      datas =
      datas = map(lambda text: text.replace('\n', ''), datas)
      for data_item in datas:
            myDocument.add_paragraph(u'%s' % data_item)
      #
      myDocument.add_paragraph()
      # 指数加1
      count += 1


# 图片计数
count = 1
# 第一次发送数据
dict_str = get_response()

# 判断cookie是否失效
login = dict_str['errmsg']
if login == '请先登录':
    input('cookie已失效,请重新获取登录后的cookie进行替换,本程序自动结束!')
    sys.exit()

# 取最大页数
page_count = dict_str['data']['pageinfo']['pagecount']
print('约%s页' % page_count)

# 获取开始页数
flag1 = True
mincount = 1
while flag1:
    min_page = input('请输入要开始获取的页数,默认值为第1页:')
    if min_page.isdigit():
      mincount = int(min_page)
      flag1 = False
    elif min_page == '':
      flag1 = False
    else:
      print('非法参数!请重新输入')

# 获取最大页数
flag2 = True
while flag2:
    max_page = input('请输入要获取的总页数,默认值为最大页数:')
    if max_page.isdigit():
      page_count = int(max_page)
      flag2 = False
    elif max_page == '':
      flag2 = False
    else:
      print('非法参数!请重新输入')

# 获取当前工作目录
root = os.getcwd()
# 拼接路径
pt = os.path.join(root, keyword)
# 如果目录不存在则创建文件夹
if not os.path.isdir(pt):
    os.mkdir(root + '\\%s' % keyword)

# 创建空白文档,并设置样式
myDocument = Document()
myDocument.styles['Normal'].font.name = u'微软雅黑'
myDocument.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'微软雅黑')

# 创建空白文件,并设置编码
f1 = open('%s.txt' % keyword, 'w', encoding='utf-8')

# 获取数据
for page in range(mincount, page_count + 1):
    print('第%s页书籍信息:' % page)
    # 发送请求
    dict_str = get_response(page)
    # 如果为空则结束发送
    if not dict_str['data']['list']:
      break

    # 把数据写入文件
    data_download(dict_str)
    # 提示信息
    print('【第%s页数据写入文件中...】' % page)
    # 延迟发送请求
    time.sleep(5)
    #

# 保存文件并关闭
f1.close()
myDocument.save('%s.doc' % keyword)
print('数据写入完毕!本程序自动结束!')

ymhld 发表于 2020-2-7 18:13

ligxi 发表于 2020-2-7 18:11
把你改的源码发个我看看

我没改呀,只加了两行注释

# -*- coding: utf-8 -*-
#by 52 ligxi
import urllib.parse
import string
import requests
import json
import re
import time
import os

# doc文档模块
from docx import Document   # 需要pip install python-docx,pip uninstall docx卸载
from docx.shared import Inches
from docx.oxml.ns import qn

# 接收用户输入的关键字
flag1 = True
keyword = ''
while flag1:
    keyword = input('请输入搜索的关键字:')
    if keyword:
      flag1 = False
    else:
      print('关键字为空,请重新输入!')

# 要发送的请求
wqxuetang_url = r'https://lib-nuanxin.wqxuetang.com/v1/search/initsearch'
# 字符转码
new_wqxuetang_url = urllib.parse.quote(wqxuetang_url, safe=string.printable)


# 发送请求
def get_response(page=1):
    # 请求头
    #
    # Cookie获取方式:
    # 在浏览器调出控制台,然后输入document.cookie即可获取。
    headers = {
      'Accept': 'application/json, text/plain, */*',
      'Accept - Encoding': 'gzip, deflate, br',
      'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
      'Connection': 'keep-alive',
      'Host': 'lib-nuanxin.wqxuetang.com',
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0',
      'Cookie': "_gid=387202506456; _gidv=a6d0c40a2586c69ee3fdc1db569c5ded; ssxmod_itna=WuD=BK7K4lfG77XxDv5DKG=OGQ0OInqitbDl=2DA5D8D6DQeGTQUPWHQCHCwNWoQ=Bb4ow9hS4tTzUCxcm5IzId4GLDmKDyb0hxPKD4bKGwD0eG+DD4DWmx03DoxGABhaTKiODQ40kDmqG2RqNDA4DjWkmhWktj/dXDxGUeIMh5WqDMD7tD/8GtXi=DGuTiXDGWQhj/SqGuDG=4wTLDx0P13GE47YvCbi3GuA+4KgG54hwqGDYeKEm5bio3UhqmpAHjXDDA0Y+feD===; ssxmod_itna2=WuD=BK7K4lfG77XxDv5DKG=OGQ0OInqitD6aIi40y…"
    }
    # 要发送的数据
    data = {
      'kw': keyword,
      'type': 1,
      'begindate': '',
      'enddate': '',
      'tid': '',
      'libclass': '',
      'cnclass': '',
      'tag': '',
      'author': '',
      'pn': page,
      'size': 10,
      'isfquery': 'undefined',
      'sort': 1
    }
    # 发送请求,带数据和请求头
    response = requests.post(url=new_wqxuetang_url, data=data, headers=headers)
    # 转为JSON对象
    dict_str = json.loads(response.text)
    return dict_str


# 保存数据
def data_download(dict_str):
    global count
    # 匹配网页标签并替换
    rec = re.compile('</?+\s?\d?/?>')
    # 写入文件
    for item in dict_str['data']['list']:
      # 分割线
      data1 = '{0}【华丽的分割线】{0}\n'.format('*' * 30)
      f1.write(data1)
      # 书ID号
      data2 = '书的ID号:%s\n' % item['numid']
      f1.write(data2)
      print('BID:%s\t' % item['numid'], end='')
      # 书名
      book_name = item['name']
      result = set(re.findall(rec, book_name))
      for ret in result:
            book_name = book_name.replace(ret, '')
      data3 = '书名:《%s》\n' % book_name
      f1.write(data3)
      print('书名:《%s》' % book_name)
      # 作者
      data4 = '作者:%s\n' % item['author']
      f1.write(data4)
      # 出版时间
      data5 = '出版时间:%s\n' % item['pubdate']
      f1.write(data5)
      # 出版社
      data6 = '出版社:%s\n' % item['pub']
      f1.write(data6)
      # 图书简介
      des = item['descript']
      result = set(re.findall(rec, des))
      for ret in result:
            des = des.replace(ret, '')
      data7 = '图书简介 :%s\n\n' % des
      f1.write(data7)
      # 刷新缓存区
      f1.flush()

      # 图片请求头
      img_headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept - Encoding': 'gzip, deflate, br',
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
            'Connection': 'keep-alive',
            'Host': 'bookask-cover.oss-cn-beijing.aliyuncs.com',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0',
            'Cookie': "_gid=387202506456; _gidv=a6d0c40a2586c69ee3fdc1db569c5ded; ssxmod_itna=WuD=BK7K4lfG77XxDv5DKG=OGQ0OInqitbDl=2DA5D8D6DQeGTQUPWHQCHCwNWoQ=Bb4ow9hS4tTzUCxcm5IzId4GLDmKDyb0hxPKD4bKGwD0eG+DD4DWmx03DoxGABhaTKiODQ40kDmqG2RqNDA4DjWkmhWktj/dXDxGUeIMh5WqDMD7tD/8GtXi=DGuTiXDGWQhj/SqGuDG=4wTLDx0P13GE47YvCbi3GuA+4KgG54hwqGDYeKEm5bio3UhqmpAHjXDDA0Y+feD===; ssxmod_itna2=WuD=BK7K4lfG77XxDv5DKG=OGQ0OInqitD6aIi40y…"
      }

      # 拿到图片的请求地址
      img_url = item['coverurl']
      # 发送请求
      img_data = requests.get(url=img_url, headers=img_headers)
      # 发送间隔
      time.sleep(1)
      # 把图片写入本地目录
      img_count = '%s\\%s.jpg' % (pt, count)
      with open(img_count, 'wb') as fp:
            fp.write(img_data.content)

      # 把书籍信息写入doc
      data1 = data1.replace('\n', '')
      myDocument.add_paragraph(data1)
      # 向文档里添加图片
      myDocument.add_picture(img_count, width=Inches(2), height=Inches(3))
      # 处理文字
      datas =
      datas = map(lambda text: text.replace('\n', ''), datas)
      for data_item in datas:
            myDocument.add_paragraph(data_item)
      #
      myDocument.add_paragraph()
      # 指数加1
      count += 1


# 图片计数
count = 1
# 第一次发送数据
dict_str = get_response()

# 取最大页数
page_count = dict_str['data']['pageinfo']['pagecount']
print('约%s页' % page_count)

# 获取页数
flag2 = True
max_page = ''
while flag2:
    max_page = input('请输入要获取的总页数,默认值为最大,从第1页开始到:')
    if max_page.isdigit() or max_page == '':
      flag2 = False
    else:
      print('非法参数!请重新输入')

# 判断要获取的最大页数
if max_page == '':
    max_page = page_count
#
max_page = int(max_page)

# 获取当前工作目录
root = os.getcwd()
# 拼接路径
pt = os.path.join(root, keyword)
# 如果目录不存在则创建文件夹
if not os.path.isdir(pt):
    os.mkdir(root + '\\%s' % keyword)

# 创建空白文档,并设置样式
myDocument = Document()
myDocument.styles['Normal'].font.name = u'微软雅黑'
myDocument.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'微软雅黑')

# 创建空白文件,并设置编码
f1 = open('%s.txt' % keyword, 'w', encoding='utf-8')

# 获取数据
for page in range(1, max_page + 1):
    print('第%s页书籍信息:' % page)
    # 发送请求
    dict_str = get_response(page)
    # 如果为空则结束发送
    if not dict_str['data']['list']:
      break

    # 把数据写入文件
    data_download(dict_str)
    # 提示信息
    print('【第%s页数据写入文件中...】' % page)
    # 延迟发送请求
    time.sleep(3)
    #

# 保存文件并关闭
f1.close()
myDocument.save('%s.doc' % keyword)
print('数据写入完毕!本程序自动结束!')

wtujcf123 发表于 2020-2-8 13:12

你好,从特定页开始下载后,下载了25个图片目录后,便会出现这个错误,请您查看一下,谢谢了,。
Traceback (most recent call last):
File "D:\获取书籍信息\wqxuetang_books-2.py", line 219, in <module>
    data_download(dict_str)
File "D:\获取书籍信息\wqxuetang_books-2.py", line 142, in data_download
    myDocument.add_paragraph(data_item)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\document.py", line 56, in add_paragraph
    return self._body.add_paragraph(text, style)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\blkcntnr.py", line 37, in add_paragraph
    paragraph.add_run(text)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\text\paragraph.py", line 37, in add_run
    run.text = text
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\text\run.py", line 163, in text
    self._r.text = text
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\oxml\text\run.py", line 104, in text
    _RunContentAppender.append_to_run_from_text(self, text)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\oxml\text\run.py", line 134, in append_to_run_from_text
    appender.add_text(text)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\oxml\text\run.py", line 143, in add_text
    self.flush()
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\oxml\text\run.py", line 165, in flush
    self._r.add_t(text)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\oxml\text\run.py", line 41, in add_t
    t = self._add_t(text=text)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\site-packages\docx\oxml\xmlchemy.py", line 273, in _add_child
    setattr(child, key, value)
File "src\lxml\etree.pyx", line 1024, in lxml.etree._Element.text.__set__
File "src\lxml\apihelpers.pxi", line 747, in lxml.etree._setNodeText
File "src\lxml\apihelpers.pxi", line 735, in lxml.etree._createTextNode
File "src\lxml\apihelpers.pxi", line 1540, in lxml.etree._utf8
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters

litengdada 发表于 2020-2-7 16:03

沙发!!!!!1

ligxi 发表于 2020-2-7 16:08

litengdada 发表于 2020-2-7 16:03
沙发!!!!!1

{:301_997:}学习学习!

cdwdz 发表于 2020-2-7 16:15

学习了虽然不懂
感谢分享谢谢

策士 发表于 2020-2-7 16:37

没有书的内容啊,简介没用的

ligxi 发表于 2020-2-7 16:40

策士 发表于 2020-2-7 16:37
没有书的内容啊,简介没用的

本来就不是获取书内容的,只是提供id和书的基础信息而已。书的内容都是图片,可以用论坛大佬的写的工具下载。{:301_1007:}

ymhld 发表于 2020-2-7 17:24

进来学习,不错的工具,有大用处,不明白的就算了

ligxi 发表于 2020-2-7 17:40

ymhld 发表于 2020-2-7 17:24
进来学习,不错的工具,有大用处,不明白的就算了

现在防得太厉害,很难批量下载了,等大佬更新下载工具后方便找书,不用去翻。{:301_973:}

ymhld 发表于 2020-2-7 17:51

ligxi 发表于 2020-2-7 17:40
现在防得太厉害,很难批量下载了,等大佬更新下载工具后方便找书,不用去翻。

有些模块安不上,
    from exceptions import PendingDeprecationWarning
ModuleNotFoundError: No module named 'exceptions'

ligxi 发表于 2020-2-7 17:54

ymhld 发表于 2020-2-7 17:51
有些模块安不上,
    from exceptions import PendingDeprecationWarning
ModuleNotFoundError: No mo ...

这不是我用的模块吧{:301_1009:},看了一下好像是Python3.8的内置模块吧?
页: [1] 2 3 4 5 6
查看完整版本: Python爬虫练习——文泉书籍信息获取[失效]