最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python面向?qū)ο蠖嗑€程爬蟲(chóng)爬取搜狐頁(yè)面的實(shí)例代碼

 更新時(shí)間:2018年05月31日 17:28:50   投稿:mrr  
這篇文章主要介紹了python面向?qū)ο蠖嗑€程爬蟲(chóng)爬取搜狐頁(yè)面的實(shí)例代碼,需要的朋友可以參考下

首先我們需要幾個(gè)包:requests, lxml, bs4, pymongo, redis

1. 創(chuàng)建爬蟲(chóng)對(duì)象,具有的幾個(gè)行為:抓取頁(yè)面,解析頁(yè)面,抽取頁(yè)面,儲(chǔ)存頁(yè)面

class Spider(object):
 def __init__(self):
  # 狀態(tài)(是否工作)
  self.status = SpiderStatus.IDLE
 # 抓取頁(yè)面
 def fetch(self, current_url):
  pass
 # 解析頁(yè)面
 def parse(self, html_page):
  pass
 # 抽取頁(yè)面
 def extract(self, html_page):
  pass
 # 儲(chǔ)存頁(yè)面
 def store(self, data_dict):
  pass

2. 設(shè)置爬蟲(chóng)屬性,沒(méi)有在爬取和在爬取中,我們用一個(gè)類(lèi)封裝, @unique使里面元素獨(dú)一無(wú)二,Enum和unique需要從 enum里面導(dǎo)入:

@unique
class SpiderStatus(Enum):
 IDLE = 0
 WORKING = 1

3. 重寫(xiě)多線程的類(lèi):

class SpiderThread(Thread):
 def __init__(self, spider, tasks):
  super().__init__(daemon=True)
  self.spider = spider
  self.tasks = tasks
 def run(self):
  while True:
   pass

4. 現(xiàn)在爬蟲(chóng)的基本結(jié)構(gòu)已經(jīng)做完了,在main函數(shù)創(chuàng)建tasks, Queue需要從queue里面導(dǎo)入:

def main():
 # list沒(méi)有鎖,所以使用Queue比較安全, task_queue=[]也可以使用,Queue 是先進(jìn)先出結(jié)構(gòu), 即 FIFO
 task_queue = Queue()
 # 往隊(duì)列放種子url, 即搜狐手機(jī)端的url
 task_queue.put('http://m.sohu,com/')
 # 指定起多少個(gè)線程
 spider_threads = [SpiderThread(Spider(), task_queue) for _ in range(10)]
 for spider_thread in spider_threads:
  spider_thread.start()
 # 控制主線程不能停下,如果隊(duì)列里有東西,任務(wù)不能停, 或者spider處于工作狀態(tài),也不能停
 while task_queue.empty() or is_any_alive(spider_threads):
  pass
 print('Over')

4-1. 而 is_any_threads則是判斷線程里是否有spider還活著,所以我們?cè)賹?xiě)一個(gè)函數(shù)來(lái)封裝一下:

def is_any_alive(spider_threads):
 return any([spider_thread.spider.status == SpiderStatus.WORKING
    for spider_thread in spider_threads])

5. 所有的結(jié)構(gòu)已經(jīng)全部寫(xiě)完,接下來(lái)就是可以填補(bǔ)爬蟲(chóng)部分的代碼,在SpiderThread(Thread)里面,開(kāi)始寫(xiě)爬蟲(chóng)運(yùn)行 run 的方法,即線程起來(lái)后,要做的事情:

 def run(self):
  while True:
   # 獲取url
   current_url = self.tasks_queue.get()
   visited_urls.add(current_url)
   # 把爬蟲(chóng)的status改成working
   self.spider.status = SpiderStatus.WORKING
   # 獲取頁(yè)面
   html_page = self.spider.fetch(current_url)
   # 判斷頁(yè)面是否為空
   if html_page not in [None, '']:
    # 去解析這個(gè)頁(yè)面, 拿到列表
    url_links = self.spider.parse(html_page)
    # 把解析完的結(jié)構(gòu)加到 self.tasks_queue里面來(lái)
    # 沒(méi)有一次性添加到隊(duì)列的方法 用循環(huán)添加算求了
    for url_link in url_links:
     self.tasks_queue.put(url_link)
   # 完成任務(wù),狀態(tài)變回IDLE
   self.spider.status = SpiderStatus.IDLE

6.  現(xiàn)在可以開(kāi)始寫(xiě) Spider()這個(gè)類(lèi)里面的四個(gè)方法,首先寫(xiě)fetch()抓取頁(yè)面里面的:  

@Retry()
 def fetch(self, current_url, *, charsets=('utf-8', ), user_agent=None, proxies=None):
  thread_name = current_thread().name
  print(f'[{thread_name}]: {current_url}')
  headers = {'user-agent': user_agent} if user_agent else {}
  resp = requests.get(current_url,
       headers=headers, proxies=proxies)
  # 判斷狀態(tài)碼,只要200的頁(yè)面
  return decode_page(resp.content, charsets) \
   if resp.status_code == 200 else None

6-1. decode_page是我們?cè)陬?lèi)的外面封裝一個(gè)解碼的函數(shù):

def decode_page(page_bytes, charsets=('utf-8',)):
 page_html = None
 for charset in charsets:
  try:
   page_html = page_bytes.decode(charset)
   break
  except UnicodeDecodeError:
   pass
   # logging.error('Decode:', error)
 return page_html

6-2. @retry是裝飾器,用于重試, 因?yàn)樾枰獋鲄?,在這里我們用一個(gè)類(lèi)來(lái)包裝, 所以最后改成@Retry():

# retry的類(lèi),重試次數(shù)3次,時(shí)間5秒(這樣寫(xiě)在裝飾器就不用傳參數(shù)類(lèi)), 異常
class Retry(object):
 def __init__(self, *, retry_times=3, wait_secs=5, errors=(Exception, )):
  self.retry_times = retry_times
  self.wait_secs = wait_secs
  self.errors = errors
 # call 方法傳參
 def __call__(self, fn):
  def wrapper(*args, **kwargs):
   for _ in range(self.retry_times):
    try:
     return fn(*args, **kwargs)
    except self.errors as e:
     # 打日志
     logging.error(e)
     # 最小避讓 self.wait_secs 再發(fā)起請(qǐng)求(最小避讓時(shí)間)
     sleep((random() + 1) * self.wait_secs)
   return None
  return wrapper()

7. 接下來(lái)寫(xiě)解析頁(yè)面的方法,即 parse():

# 解析頁(yè)面
 def parse(self, html_page, *, domain='m.sohu.com'):
  soup = BeautifulSoup(html_page, 'lxml')
  url_links = []
  # 找body的有 href 屬性的 a 標(biāo)簽
  for a_tag in soup.body.select('a[href]'):
   # 拿到這個(gè)屬性
   parser = urlparse(a_tag.attrs['href'])
   netloc = parser.netloc or domain
   scheme = parser.scheme or 'http'
   netloc = parser.netloc or 'm.sohu.com'
   # 只爬取 domain 底下的
   if scheme != 'javascript' and netloc == domain:
    path = parser.path
    query = '?' + parser.query if parser.query else ''
    full_url = f'{scheme}://{netloc}{path}{query}'
    if full_url not in visited_urls:
     url_links.append(full_url)
  return url_links

7-1. 我們需要在SpiderThread()的 run方法里面,在

current_url = self.tasks_queue.get()

下面添加

visited_urls.add(current_url)

在類(lèi)外面再添加一個(gè)

visited_urls = set()去重

8. 現(xiàn)在已經(jīng)能開(kāi)始抓取到相應(yīng)的網(wǎng)址。

 

總結(jié)

以上所述是小編給大家介紹的python面向?qū)ο蠖嗑€程爬蟲(chóng)爬取搜狐頁(yè)面的實(shí)例代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • K近鄰法(KNN)相關(guān)知識(shí)總結(jié)以及如何用python實(shí)現(xiàn)

    K近鄰法(KNN)相關(guān)知識(shí)總結(jié)以及如何用python實(shí)現(xiàn)

    這篇文章主要介紹了K近鄰法(KNN)相關(guān)知識(shí)總結(jié)以及如何用python實(shí)現(xiàn),幫助大家更好的利用python實(shí)現(xiàn)機(jī)器學(xué)習(xí),感興趣的朋友可以了解下
    2021-01-01
  • python可視化分析的實(shí)現(xiàn)(matplotlib、seaborn、ggplot2)

    python可視化分析的實(shí)現(xiàn)(matplotlib、seaborn、ggplot2)

    這篇文章主要介紹了python可視化分析的實(shí)現(xiàn)(matplotlib、seaborn、ggplot2),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • python 爬蟲(chóng)網(wǎng)頁(yè)登陸的簡(jiǎn)單實(shí)現(xiàn)

    python 爬蟲(chóng)網(wǎng)頁(yè)登陸的簡(jiǎn)單實(shí)現(xiàn)

    這篇文章主要介紹了python 爬蟲(chóng)網(wǎng)頁(yè)登陸的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • python3字符串操作總結(jié)

    python3字符串操作總結(jié)

    這篇文章主要介紹了python3字符串操作總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Python中的pprint打印模塊

    Python中的pprint打印模塊

    這篇文章主要介紹了Python中的pprint打印模塊,??pprint()??采用分行打印輸出,下文關(guān)于其相關(guān)介紹,需要的小伙伴可以參考一下
    2022-05-05
  • Python中每次處理一個(gè)字符的5種方法

    Python中每次處理一個(gè)字符的5種方法

    這篇文章主要介紹了Python中每次處理一個(gè)字符的5種方法,即把字符串分割成字符數(shù)組或把字符串切割成單獨(dú)字符的方法,需要的朋友可以參考下
    2015-05-05
  • 多個(gè)python文件調(diào)用logging模塊報(bào)錯(cuò)誤

    多個(gè)python文件調(diào)用logging模塊報(bào)錯(cuò)誤

    這篇文章主要介紹了多個(gè)python文件調(diào)用logging模塊產(chǎn)生錯(cuò)誤,需要的朋友可以參考下
    2020-02-02
  • 詳解Python實(shí)現(xiàn)按任意鍵繼續(xù)/退出的功能

    詳解Python實(shí)現(xiàn)按任意鍵繼續(xù)/退出的功能

    在學(xué)Python時(shí)在總想實(shí)現(xiàn)一個(gè)按任意鍵繼續(xù)/退出的程序(受.bat毒害), 奈何一直沒(méi)有寫(xiě),今天抽時(shí)間寫(xiě)出來(lái)了,下面分享給大家,有需要的可以參考借鑒。
    2016-08-08
  • python優(yōu)雅實(shí)現(xiàn)代碼與敏感信息分離的方法

    python優(yōu)雅實(shí)現(xiàn)代碼與敏感信息分離的方法

    這篇文章主要介紹了python優(yōu)雅實(shí)現(xiàn)代碼與敏感信息分離的方法,在flask中,python-dotenv 可以無(wú)縫接入項(xiàng)目中,只要你的項(xiàng)目中存在 .env 或者 .flaskenv 文件,他就會(huì)提示你是否安裝 python-dotenv,需要的朋友可以參考下
    2022-05-05
  • java虛擬機(jī)中棧的運(yùn)行知識(shí)點(diǎn)總結(jié)

    java虛擬機(jī)中棧的運(yùn)行知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是一篇關(guān)于java虛擬機(jī)中棧的運(yùn)行知識(shí)點(diǎn)總結(jié),有需要的朋友們可以學(xué)習(xí)參考下。
    2021-06-06

最新評(píng)論

永顺县| 葫芦岛市| 墨脱县| 东明县| 银川市| 辽阳县| 平乐县| 罗江县| 固镇县| 陆川县| 湾仔区| 辰溪县| 武平县| 台东市| 安阳县| 晋州市| 保康县| 宁武县| 东源县| 肃北| 普洱| 克东县| 金堂县| 娱乐| 尚志市| 雷山县| 塔河县| 文山县| 辛集市| 西平县| 宝鸡市| 大化| 清苑县| 上饶县| 息烽县| 台东市| 宁晋县| 含山县| 逊克县| 舒城县| 洞头县|