Python轻松爬取百度搜索信息
前段时间一个粉丝加我好友,希望能让我帮忙做一些事情,就是对百度的搜索结果进行采集,同时对格式进行处理,至于具体的用处我也没有太关注,毕竟粉丝也包了一个大红包,希望他能发财吧,今天就大概的把源码的实现过程进行分析,展示下。
粉丝之前也找了两个人帮忙开发,最终的结果估计是不了了之,钱花了没有结果,所以找到我,从目前的的粉丝反馈来看对结果还是满意是的,能完成他的需求,也能得到不错的结果。
需求
一、 在搜索引擎中搜索一个长尾关键词,采集排在前三名的文章标题和正文内容,然后把这三篇文章保存到同一个txt格式文本里面。此txt文本名为当前搜索词。文章内容段落分明。或者保持它原始段落。目的是可以有良好的阅读体验。
二、 只采集有正文内容的详情页,如果排名前三的是网站首页 或者是列表页 、或者是 百度图片、百度地图、阿拉丁等内容 ,可直接可以跳过,接着往下判断,直到采集到三篇有实质性文章内容的页面。如:排名前三的是知乎 百度知道等网站,只采集一楼用户回答的内容即可。
三、 可以导入多个(几千个几万个)搜索的长尾关键词,以txt方式导入、或 表格方式导入。可以选择采集下来生成文章的保存位置。
截图详细说明:以搜索” 深圳化妆培训学校哪家比较好”为例。
问题分析
因为每个网站的结构不一样,所以想要写出通用的代码是不行的,所以需要对网站定制,每个特殊的网站可以写专用的解析器,这样才能完美的完成粉丝的需求。
首先用粉丝给的几个关键字,做了一波搜索,然后分析了一波,成功的引出了粉丝新的需求,对 知乎 百度知道 百家号这样的网站每个回答需要取出第一条答案
然后在讨论一波后锁定需要将内置的网站的答案前置,比如搜索之后又10条,即使内置网站的答案不在最前面,也要优先内置网站的数据
因为需要内置一些网站,为了更好的解析,所以需要定制解析器,好在粉丝会一些html知识,所以我提供了内置的教程,方便后续粉丝增加网站
源码展示
环境:
python3.5 requests 还有 BeautifulSoup
源码
import requests
from bs4 import BeautifulSoup
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, compress',
'Accept-Language': 'en-us;q=0.5,en;q=0.3',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'
} # 定义头文件,伪装成浏览器
global index
keyword = ''
maxCount = 3
# 百家号
def readBaijiahao():
return True,'div', {"class": ["article-content", "index-module_articleWrap_2Zphx"]}
# 百度知道
def readBaiduAsk():
return False,'div', {"accuse": ["aContent"]}
# 知乎
def readZhihu():
return True,'div', {
"class": ["RichContent-inner", "RichText ztext Post-RichText", "RichText ztext Post-RichText css-hnrfcf"]}
readerMap = {
"baijiahao.baidu.com": readBaijiahao(),
"zhihu.com": readZhihu(),
"zhidao.baidu.com": readBaiduAsk()
# 插入到这里
}
class Spide:
def __init__(self):
self.index = 0
self.keyword = ''
self.defineSite = []
self.commoneSite = []
def readFile(self):
with open("query.txt", "r", encoding='utf-8') as f:
data = f.readlines()
return data
def get_content(self, url):
try:
response = requests.get(url, headers=headers)
response.raise_for_status() # 如果返回的状态码不是200, 则抛出异常;
response.encoding = 'gb2312' # 判断网页的编码格式, 便于respons.text知道如何解码;
except Exception as e:
print("爬取错误")
else:
print(response.url)
print("爬取成功!")
content = response.text
return content
def write2File(self, article):
fileName = "doc/" + self.keyword + '.txt'
with open(fileName, 'a+', encoding='utf-8') as f:
if self.index != 0:
f.write('\n' + self.keyword + '\n'+ '\n')
for line in article:
f.write(line)
f.write( '\n\n')
f.writelines('\n')
def readContent(self, div,readP):
if div is None:
return False
article = []
hasText = False
if readP:
pList = div.find_all('p')
for x in pList:
if len(x.text.lstrip()) != 0:
hasText = True
article.append(x.text.lstrip().replace('\n', '').replace(' ', ''))
else:
con = div.text.lstrip().replace('\n', '').replace(' ', '')
hasText = len(con)>0
article.append(con)
if hasText:
self.write2File(article)
return hasText
# if hasText:
# self.write2File(article)
# return hasText
def readCache(self, cacheContent):
soup = BeautifulSoup(cacheContent, 'html.parser')
try:
srcSite = soup.find('div', id='bd_snap_note').find('a')['href']
# if readerMap.has_key()
isDefineSite = False
for defineSite in readerMap.keys():
if srcSite.find(defineSite) != -1:
self.defineSite.append({soup: readerMap.get(defineSite)})
isDefineSite = True
break
if not isDefineSite:
self.commoneSite.append(soup)
except:
pass
def getItem2(self, content):
# # 实例化soup对象, 便于处理;
soup = BeautifulSoup(content, 'html.parser')
# 百度快照
divObj = soup.find_all('a', attrs={'data-click': "{'rsv_snapshot':'1'}"})
for h3 in divObj:
gwList = h3.parent.parent.find_all('a')
isGw = False
for aLink in gwList:
if aLink['href'] == "http://trust.baidu.com/vstar/official/intro?type=gw":
isGw = True
break
if isGw:
continue
# h3
if h3.next_sibling != None and h3.next_sibling.next_sibling != None and h3.next_sibling.next_sibling.text == '翻译此页':
continue
href = h3.get('href')
cacheContent = self.get_content(href)
self.readCache(cacheContent)
if len(self.defineSite) > 0 and self.index < maxCount:
for item in self.defineSite:
soup, readerTuple = item.popitem()
div = soup.find(readerTuple[1], readerTuple[2])
if self.readContent(div,readerTuple[0]):
self.index = self.index + 1
if self.index >= maxCount:
break
# 如果想使用通用的解析可以打开下面的代码
# if len(self.commoneSite) > 0 and self.index < maxCount:
# for soup in self.commoneSite:
# self.index = self.index + 1
# bodyStr = soup.find('body').text.strip().replace('\n', '').replace(' ', '')
# self.write2File(bodyStr)
# if self.index >= maxCount:
# break
def searchKeyword1(self, keyword):
self.keyword = keyword
self.index = 0
self.defineSite.clear()
self.commoneSite.clear()
url = 'http://www.baidu.com.cn/s?ie=utf-8&f=8&rsv_bp=1&ch=11&tn=98010089_dg&wd=' + keyword + '&pn=0&rqlang=cn&rsv_dl=tb&rsv_sug3=1&rsv_sug2=0&rsv_btype=t&inputT=769&rsv_sug4=769&rsv_jmp=slow'
# url = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&ch=11&tn=98010089_dg&wd=python%20%E7%99%BE%E5%BA%A6%E6%90%9C%E7%B4%A2&oq=python%2520%25E7%2599%25BE%25E5%25BA%25A6&rsv_pq=a624eea1000fb87b&rsv_t=2e3dlaNMWUbo7mECejoQwxZykgFnOYIZq64YSw0RugY%2FO1ONhHN6xF8IC%2B97V8NHxCY&rqlang=cn&rsv_dl=tb&rsv_sug3=1&rsv_sug2=0&rsv_btype=t&inputT=769&rsv_sug4=769&rsv_jmp=slow'
content = self.get_content(url)
# time.sleep(3)
if content is not None:
self.getItem2(content)
if __name__ == '__main__':
spide = Spide()
keywordList = spide.readFile()
for keyword in keywordList:
keyword = keyword.strip('\n') # 去掉列表中每一个元素的换行符
spide.searchKeyword1(keyword)
复制代码
总结:
爬取数据很简单,中间也遇到了一些问题,在和粉丝的沟通中需求在变更,大概的代码就像下面这样
- 点赞
- 收藏
- 关注作者
评论(0)