首先先分享下github这篇文章吧,参考了部分代码,但我想做一个很详细的解读。新版百度文库爬虫 · Jack-Cherish/[email protected]github.com
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5ybjlGcp9VN0MGM4QWZkZDOhRTMyEWZ5MmZiN2NlFWNhJDOhRzNw0iM29CXt92YucWbphmeuIzYpB3Lc9CX6MHc0RHaiojIsJye.jpg)
首先,我想自动化打开百度文库的页面(其实这一步,并不需要,经实践得知)。
不过,我觉得这一步算是初级的对selenium理解,希望对大家有所帮助。
第一步的流程:自动化打开百度文库网页 -> 将窗口下滑到“继续阅读”的按钮处 -> 自动点击 -> 显示完整页面。
def auto_page_search(url):
print('开始自动查询网页')
browser = webdriver.Chrome()
# browser.get('https://wenku.baidu.com/view/dcfab8bff705cc175527096e.html')
browser.get(url)
print('等待5秒')
time.sleep(5)
# 下面这个语句并不是查找“继续阅读”按钮所在位置,而是更上面的元素,因为按照原本元素位置滑动窗口会遮挡住,大家可以试一试
eles = browser.find_element_by_xpath('//*[@id="html-reader-go-more"]/div[1]/div[3]/div[1]')
browser.execute_script('arguments[0].scrollIntoView();', eles)
print('等待2秒')
time.sleep(2)
#点击“继续阅读”按钮
browser.find_element_by_xpath('//*[@id="html-reader-go-more"]/div[2]/div[1]/span/span[2]').click()
print('已显示文档所有内容')
接着,欸我们就想着定义一个可以抓取网页源代码的函数,以便于我们后面的爬取,这个函数很重要。
def fetch_url(url):
''':return: 网页源代码'''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'}
session = requests.session()
sourse = session.get(url, headers=headers).content.decode('gbk')
return sourse
这里用的是 session 方法,不过我认为直接 request.get 也 OK ,看个人喜好了。
doc ,txt ,pdf ppt 的爬取方式有些差异,而且都很奇怪。
先介绍 txt 格式的文库如何爬取:
我们打开一个文档,如下:
好吧我们现在话不多说,直接打开开发者工具。
大家不能被 Element 中显示有文档的内容,就想着直接用什么正则、xpath等暴力爬取源代码了,这里显示的内容,是经过一系列渲染以后,展示在我们面前的,右键打开网页源代码,会发现根本没有什么文字内容。
那我们看一下真正的文字内容在哪里?很难找,就在下面的加载文件里:
敢信?没错就是这么长一个文件,URL 中的红线(可能没标好)显示的部分,是需要我们获取的,比如 md5 ,rsign 等,然后构成这个 URL 。
可能有人问了,我们都能找到这个文件,为什么不直接用呢?偏要找到那些 md5 、rsign 。因为我们是希望直接输入百度文档的地址,就直接自动生成 txt 文件,而不是每一次费很大劲找到这个加载文件。当然如果不嫌麻烦的话你也可以这样做。
所以我们应该找到 network 中第一个文件,它里面显示的就是网页的源代码。找到下图。
获取其中的 title 、docId 、docType 。代码如下:
def get_Id(sourse):
Id=re.findall(r"docId.*?\:.*?\'(.*?)\'\,",sourse)[0]
return Id
def get_Type(sourse):
Type=re.findall(r"docType.*?\:.*?\'(.*?)\'\,",sourse)[0]
return Type
def get_Title(sourse):
Title=re.findall(r"title.*?\:.*?\'(.*?)\'\,",sourse)[0]
return Title
我们获取这些东西干啥呢?当然是获取 rsign 等信息了。
接下来我们要获取的信息在下面这个加载文件里:
不过这个链接我们最后的一部分可以不要,我们利用正则表达式获取 rsign 等信息,就可以拼接起正文内容的链接。
流程差不多就是上面这样,最后就是获取正文内容。
正文内容是 json 格式的,需要改变一些换行符等排版,接着保存就好,代码如下:
def parse_txt(Id):
''':param Id: 之前爬取的 docId'''
url1='https://wenku.baidu.com/api/doc/getdocinfo?callback=cb&doc_id={}'.format(Id)
content1=fetch_url(url1)
md5=re.findall('"md5sum":"(.*?)"',content1)[0]
pn=re.findall('"totalPageNum":"(.*?)"',content1)[0]
rsign=re.findall('"rsign":"(.*?)"',content1)[0]
url2 = 'https://wkretype.bdimg.com/retype/text/' + Id + '?rn=' + pn + '&type=txt' + md5 + '&rsign=' + rsign
content2=json.loads(fetch_url(url2))
result=''
for items in content2:
for item in items:
result=result+item['c'].replace('\\r','\r').replace('\\n','\n')
return result
#保存为 txt 文件
def save_file(filename, content):
with open(filename, 'w', encoding='utf-8') as f:
f.write(content)
print('已保存为:' + filename)
txt 文档基本就上面这样了,有的 url 链接可以去掉部分数字,所以看起来比原有的 url 更短。
接着是 doc 文件:
doc 的爬取借鉴了开头高手的代码,所以这里只想做个解读。
def parse_doc(content):
result = ''
url_list = re.findall('(https.*?0.json.*?)\\\\x22}', content)
url_list = [addr.replace("\\\\\\/", "/") for addr in url_list]
for url in url_list[:-5]:
content = fetch_url(url)
y = 0
txtlists = re.findall('"c":"(.*?)".*?"y":(.*?),', content)
for item in txtlists:
if not y == item[1]:
y = item[1]
n = '\n'
else:
n = ''
result += n
result += item[0].encode('utf-8').decode('unicode_escape', 'ignore')
return result
下面一步一步解释。
这个函数需要输入一个 content ,这个东西是代表网页源代码,在这里就是文档所在位置的网页源代码。
好的我们看下面这一句:
url_list = re.findall('(https.*?0.json.*?)\\\\x22}', content)
这个东西运行完,实际就是找到了下面这些内容:
要这些东西干嘛?我们看到下一个句子:
url_list = [addr.replace("\\\\\\/", "/") for addr in url_list]
就变成了一个个可以点击的 url 地址了,实际上对应的就是 Network 中加载文件的下图:
但是我们发现下面的一句:for url in url_list[:-5]
为什么只循环到倒数第五个呢?这里我们首先确保点击了“继续阅读”按钮,查找相关文件,发现最后一个符合要求的加载文件正好是 url_list 列表对应的倒数第五个元素。
说明 url_list 中最后面的元素并不是我们想要的东西。
后面的代码就是关于如何爬取 json 格式的字符串了以及保存(doc 文档同样在这里以 txt 文件保存),就不多解读了。
以及百度文库的 PPT PDF 爬取实在不想写了,模式和爬取 txt 文档类似。
说实话,感觉百度文库的爬取实在有点让人摸不清头脑,只求看懂以及思维的跳跃能够跟上。也算记录了一种心得吧。
最后附上 main()函数。
def main():
url1 = input('请输入需要爬取的文库地址:')
auto_page_search(url1)
sourse=fetch_url(url1)
Id=get_Id(sourse)
Type=get_Type(sourse)
Title=get_Title(sourse)
if Type=='txt':
result=parse_txt(Id)
save_file(Title+'.txt',result)
elif Type=='doc':
result=parse_doc(sourse)
save_file(Title+'doc',result)