需求分析
先來看一下目標(biāo)網(wǎng)站。

這次爬取的內(nèi)容是通過搜狗微信的接口獲取微信文章的 url 然后提取目標(biāo)文章的內(nèi)容及公眾號信息。
可以指定內(nèi)容進(jìn)行爬取
那這次需要解決的問題有哪些呢?
需要解決的問題
搜狗微信在沒有登錄的情況下可以爬取十頁信息,我們想要獲取更多的信息只能登錄。在登錄的情況下,爬取數(shù)據(jù)量太大會被封 IP 。這里給出的解決方案是使用代理池的方法。我這里是自己搭建了一個(gè)小的IP代理池,在我以前的文章里有詳細(xì)的描述,可以 點(diǎn)這里 查看。
代碼演示
proxy = None # 聲明代理為 None 也就是開始的時(shí)候用本機(jī)的ip爬取
count_max = 5 # 設(shè)置一個(gè)連接錯(cuò)誤,如果連接超過五次都出錯(cuò)就停止爬取,要不然程序陷入死循環(huán)。
# 請求頭的設(shè)置要加上cookie
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
# 獲取代理
def get_proxy():
proxy = GetIP()
return proxy.get_random_ip()
# 請求頁面,這里主要使用了代理,一開始使用的是本機(jī)代理,被封之后換個(gè)ip來爬。
def get_request(url,count=1):
global proxy
if count >= count_max:
print('請求太多次了,這個(gè)方法不行啦,換換吧')
try:
if proxy:
proxies = {'http': 'http://' + proxy}
r = requests.get(url, headers=headers,proxies=proxies, allow_redirects=False)
else:
print('第一次請求,使用本機(jī)的ip')
r = requests.get(url,headers=headers,allow_redirects=False)
if r.status_code == 200:
print('第一頁')
return r.text
if r.status_code == 302:
print('狀態(tài)碼302了,快換代理吧')
proxy = get_proxy()
if proxy:
print('正在使用代理爬取', proxy)
return get_request(url)
else:
print('獲取代理出錯(cuò)')
return None
except ConnectionError as e:
count += 1
proxy = get_proxy()
return get_request(url,count)
解釋
這里是整個(gè)代碼的核心,我們先用本機(jī)的 ip 來爬取數(shù)據(jù),如果爬取的量大起來,會封 ip ,然后 url 會重定向到輸入驗(yàn)證碼的頁面,我們可以根據(jù)狀態(tài)碼是 302 來判斷這一情況,然后使用代理。并遞歸調(diào)用函數(shù)本身用ip來爬。
有些時(shí)候狀態(tài)碼不是302,也不是200 ,這時(shí)候就是連接的問題,我們也使用代理來解決這一問題。并計(jì)數(shù),連接出現(xiàn)問題的次數(shù)超過五次就停止,這樣的情況下是別的問題,不要讓在自己調(diào)用自己死循環(huán),退出重新檢查代碼邏輯。
我的代碼里面沒有加 cookie ,使用的時(shí)候加上cookie 才能爬取十頁以后的內(nèi)容。
# 解析頁面得到微信文章的詳情url
def parse_page(html):
data = etree.HTML(html)
li = data.xpath('//ul[@class="news-list"]/li')
for i in li:
url = i.xpath('./div[2]/h3[1]/a/@href')[0]
parse_detial(url)
break
# 解析詳情頁獲取微信公眾號標(biāo)題,作者,內(nèi)容。
def parse_detial(url):
response = requests.get(url,headers=headers)
if response.status_code == 200:
html = etree.HTML(response.text)
title = html.xpath('//h2[@id="activity-name"]/text()')
if title:
title = title[0].strip()
wechat_name = html.xpath('//a[@id="js_name"]/text()')
if wechat_name:
wechat_name = wechat_name[0].strip()
wechatid = html.xpath('//span[@class="profile_meta_value"]/text()')[0]
# 獲取內(nèi)容,xpath 雖然好用,但是這一時(shí)半會也沒找到怎么獲取文章內(nèi)容的方法,就用 pyquery 吧,其實(shí)就是css選擇器
doc = pq(response.text)
content = doc('.rich_media_content').text()
result = {'title':title,
'wechat_name':wechat_name,
'wechatid':wechatid,
'content':content}
print(result)
#
# 不適合導(dǎo)出CSV格式,應(yīng)該導(dǎo)出json格式
# ws = [title,wechat_name,wechatid,content]
# print(ws)
# with open('weixin_article.csv','a',newline='') as f:
# writer = csv.writer(f)
# writer.writerow(ws)
def main():
# 處理翻頁
for page in range(1):
KEYWORD = '數(shù)據(jù)分析' # 這里可以更改關(guān)鍵字
url = 'https://weixin.sogou.com/weixin?query='+ KEYWORD + '&type=2&page={}'.format(page)
html = get_request(url)
parse_page(html)
if __name__ == '__main__':
main()
這之后的代碼就是常規(guī)的爬蟲寫法,并沒有什么說道。
這里我用 xpath 沒有獲取到文章的內(nèi)容,用了 pyquery 這個(gè)解析庫,其實(shí)就是css 選擇器。應(yīng)該用xpath 也是可以獲取到內(nèi)容的,可能是沒有想到怎么寫,技術(shù)還是要在鍛煉呀。
這里存儲爬取下來的數(shù)據(jù)就沒有再寫下去了,跟之前的一樣就好了,存到mongodb 。我主要是復(fù)習(xí)一下代理 ip 的使用。
本文完!