python爬⾍爬取搜狗⽂章(代理池+re从跳转链接中到真实URL问题)
作者最近在学习python爬⾍,在爬取⽂章这个实战项⽬中遇到了⼀些⼩问题,所以写这篇⽂章来记录⼀下,顺便分享⼀下爬取过程。selenium获取cookie
整体思路
我们选择从搜狗的界⾯(‘weixin.sogou/’)来获取⽂章的基本信息,由于搜狗有反爬措施,采⽤代理池,先将搜狗搜索的结果页的源码爬取,之后解析出这⼀页的⽂章链接,翻页,继续解析⾄最后⼀页,最后访问⽂章链接获取源码提取所需信息保存到MongoDB中
准备⼯作
代理池ProxyPool:代理池的作⽤是⽤来应对sougo的反爬⾍措施,当你快速翻页时搜狗会跳出验证码识别,这时的⽹页请求会由200变成302的错误状态,这表⽰现在的ip被搜狗察觉并且不能再使⽤它来爬取。
代理池中有许多免费公开的ip,我们从代理池中不断获取ip来保证过程中有可⽤的ip供我们使⽤,这⾥使⽤的是github上公开的代理池代码附上链接,链接中有使⽤⽅法,⼤家可以⾃⾏下载运⾏:‘github/Python3WebSpider/ProxyPool’
第三⽅库:除了代理池的中的库,还需要⽤到re库(正则表达式库)requests库(get⽹页源
码)BeautifulSoup(解析)pymongo(mongodb数据库存取)
MongoDB数据库:⾮必须,可以选择其它的数据库或者⽂件类型存储
第⼀步:获取搜索结果界⾯的源码
由于是静态页⾯,⽤requests库就可以很⽅便的爬取,但需要注意两点:1.搜索中如果不登录vx只能爬取⼗页的内容 2.需要在出现302的状态码时从代理池中获取新的ip
解决第⼀个问题需要对headers进⾏设置,这⾥简单得设置User-Agent和Cookie达到需求
解决第⼆个问题采⽤从代理池的端⼝中获取ip
附代码及注释:
proxy_url ='127.0.0.1:5555/random'#获取代理ip的端⼝
proxy_ip =None#访问⽤的ip-全局变量
base_url ='weixin.sogou/weixin'
headers ={
'Cookie':'⾃⼰的cookie',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
}
keyword ='风景'
def get_proxy_ip():
"""
从代理池的端⼝获取代理ip
:return: 代理ip
"""
try:
req = (proxy_url)
if req.status_code ==200:
return None
except ConnectionError:
return None
def get_html(url,ke):
"""
:param url: 搜狗的前缀
:param ke: 搜索的关键词和页数信息
:
return: 页⾯的源码
"""
global  proxy_ip
try:
proxy_ip = get_proxy_ip()#获取⼀个ip
proxies ={'http':''+proxy_ip}#使⽤该ip访问
req = (url,params=ke,headers = headers,proxies = proxies,allow_redirects =False)#最后⼀个参数是防⽌反爬⾃动跳转页⾯if req.status_code ==200:
if req.status_code ==302:#反爬⽣效,状态码错误
proxy_ip = get_proxy_ip()
if proxy_ip:
print('use proxy',proxy_ip)
return get_html(url,ke)#当代理池的公开ip被占⽤,此处会循环获取直⾄有可⽤ip
else:
print('get proxy error')
return None
第⼆步:实现翻页,获取每⼀页的源码
这⾥只需要改变页数,也就是之前的ke参数即可
def get_index(keyword,page):
"""
主要⽤于定位关键词和页数
:param keyword: 查关键词
:
param page: 页数
:return:
"""
ke ={'query': f'{keyword}',
'type':'2',
'page':f'{page}'}
html = get_html(base_url,ke)
return html
通过运⾏以下代码即可获取100页的源码
def main():
for i in range(1,101):
html = get_index(f'{keyword}',i)
第三步:解析尝试获得⽂章的url
此时我们已经获取了每⼀页的html变量,现在对每⼀页的html结构进⾏分析,到可能存储着⽂章url的信息
通过右键检查链接,我们发现每⼀个⽂章信息都储存在class为‘news-list’下的< li >中,⽽链接在< li >的< a >标签的href属性中,点击链接,我们成功跳转到了⽂章界⾯
但如果细⼼的话会发现这个⽂章界⾯的url和之前显⽰的url不同,但显然我不细⼼,⽅便区分,称这个是跳转url
但不论怎样,我们都需要将这个url提取出来
def find_url(html):
"""
到⽂章的跳转url
:param html: 搜索页⾯html
:return: ⽂章的url(跳转)列表
"""
arti_url =[]
soup = BeautifulSoup(html,"html.parser")
ul = soup.find('ul',class_ ='news-list')
li_items = ul('li')
for i in li_items:
a = i.find('a',target='_blank')
#('href'))
arti_url.('href'))
return arti_url
然后当我进⾏下⼀步,获取该url的源码时,我发现不是我想要的界⾯
第四步:通过re获得真实url
此时我并没有管这个url爬出来的是什么,然后终于发现了两者的url是不同的,显然⽂章的页⾯是异步加载出来(好像是这么叫??初学俺也不懂)。
⽽⾯临这种情况,我脑⼦⾥只有分析ajax和⽤selenium,但我要分析1000页的ajax吗…so我只尝试了selenium,但selenium⽤⾕歌驱动时会直接被搜狗发现是⾃动化程序,原因好像是有的js⽂件中包含着驱动⽂件的名字(经后续其它项⽬学习中发现有时使⽤⽕狐驱动不会被发现)所以这两种⽅法初步尝试失败
这时我注意到了跳转url的源码有⼀部分长这样
然后我对⽐了⼀下跳转后的最终url就是这⼀串连起来,我⾼兴了起来
看到这格式整齐的字符串,⼀串正则表达式就敲了出来:
def find_true_url(html):
"""
从跳转url中解析出真正的url
:param html:
:return:
"""
n_url =''
#part = re.findall(r'\+\=\ \'.{11}', html)
parts = re.findall(r'\+\=\ \'.+', html)
for i in parts:
n_url += i[4:-3]
place("@","")
#print(n_url)
return n_url
⾄此我们得到了⽂章的真正url
第五步:从真实url获取想要的⽂章信息
这⾥只解析了简单的⽂章名称、名称,解析⽅法和查跳转url那⾥相同,想获取更多的信息也可以⾃⼰再加
def parse_arti(html,url):
"""
:param html: ⽂章html
:param url: ⽂章真实url
:return: ⽂章中需要提取的信息(字典型)
"""
soup = BeautifulSoup(html,"html.parser")
#print(soup)
try:#⼀定要加try except结构不然有的链接是视频⽂章不符合解析规定会卡住
art ={
'⽂章名称': soup.find(id='activity-name').place('\n','').replace(' ',''),
'': soup.find(id='js_name').place('\n','').replace(' ',''),
'链接':url
}
return art
except:
return None
第六步:存储到数据库
这⾥因为是字典类型,所以就存储到了MongoDB,也可以选择不⽤字典存储然后写⼊别的⽂件。这⾥需要配置⼀下MongoDB和写⼀下写⼊的⽅法
MONGO_URL ='localhost'
MONGO_DB ='vx'
MONGO_TABLE ='article'
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]#注意中括号
def save_to_mongo(art):
try:
if db[MONGO_TABLE].insert(art):
print('保存成功',art)
except Exception:
print('存储失败',art)
运⾏
此时注意,运⾏前要先运⾏代理池,不然⽆法获取代理ip
运⾏代码及数据库截图如下:
if __name__ =='__main__':
for i in range(1,101):
html = get_index(f'{keyword}', i)
arti_url = find_url(html)
#print(arti_url)
for url in arti_url:
html = get_arti_info(url)
n_url = find_true_url(html)
n_html = get_arti_info(n_url)
art = parse_arti(n_html, n_url)
save_to_mongo(art)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。