python 대상 다 중 스 레 드 파충류 가 수호 페이지 의 인 스 턴 스 코드 를 찾 습 니 다.

우선 몇 개의 가방 이 필요 합 니 다:requests,lxml,bs4,pymongo,redis
1.파충류 대상 을 만 드 는 몇 가지 행동:페이지 캡 처,페이지 분석,페이지 추출,페이지 저장

class Spider(object):
 def __init__(self):
  #   (    )
  self.status = SpiderStatus.IDLE
 #     
 def fetch(self, current_url):
  pass
 #     
 def parse(self, html_page):
  pass
 #     
 def extract(self, html_page):
  pass
 #     
 def store(self, data_dict):
  pass
2.파충류 속성 을 설정 합 니 다.기어 오 르 거나 기어 오 르 는 중 에 없습니다.우 리 는 하나의 종류 로 포장 합 니 다.@unique 는 안에 있 는 요 소 를 하나 밖 에 없 게 합 니 다.Enum 과 unique 는 enum 에서 가 져 와 야 합 니 다.

@unique
class SpiderStatus(Enum):
 IDLE = 0
 WORKING = 1
3.다 중 스 레 드 를 다시 쓰 는 클래스:

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.현재 파충류 의 기본 구조 가 완료 되 었 습 니 다.main 함수 에서 tasks 를 만 들 고 Queue 는 queue 에서 가 져 와 야 합 니 다.

def main():
 # list   ,    Queue    , task_queue=[]     ,Queue        ,   FIFO
 task_queue = Queue()
 #       url,        url
 task_queue.put('http://m.sohu,com/')
 #         
 spider_threads = [SpiderThread(Spider(), task_queue) for _ in range(10)]
 for spider_thread in spider_threads:
  spider_thread.start()
 #          ,        ,     ,   spider      ,    
 while task_queue.empty() or is_any_alive(spider_threads):
  pass
 print('Over')
4-1.그리고 isany_threads 는 스 레 드 에 spider 가 살 아 있 는 지 판단 하기 때문에 함수 하 나 를 더 써 서 포장 합 니 다.

def is_any_alive(spider_threads):
 return any([spider_thread.spider.status == SpiderStatus.WORKING
    for spider_thread in spider_threads])
5.모든 구 조 를 다 썼 습 니 다.그 다음 에 파충류 부분 을 메 울 수 있 는 코드 입 니 다.SpiderThread(Thread)에서 파충류 가 run 을 실행 하 는 방법,즉 스 레 드 를 한 후에 해 야 할 일 을 쓰기 시 작 했 습 니 다.

 def run(self):
  while True:
   #   url
   current_url = self.tasks_queue.get()
   visited_urls.add(current_url)
   #     status  working
   self.spider.status = SpiderStatus.WORKING
   #     
   html_page = self.spider.fetch(current_url)
   #         
   if html_page not in [None, '']:
    #        ,     
    url_links = self.spider.parse(html_page)
    #           self.tasks_queue   
    #                       
    for url_link in url_links:
     self.tasks_queue.put(url_link)
   #     ,    IDLE
   self.spider.status = SpiderStatus.IDLE
6.  이제 Spider()클래스 의 네 가지 방법 을 쓸 수 있 습 니 다.먼저 fetch()를 써 서 페이지 안의 것 을 캡 처 할 수 있 습 니 다.  

@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)
  #      ,  200   
  return decode_page(resp.content, charsets) \
   if resp.status_code == 200 else None
6-1. decode_page 는 우리 가 클래스 밖에서 디 코딩 을 봉인 하 는 함수 입 니 다.

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 는 장식 기 입 니 다.다시 시도 하 는 데 사 용 됩 니 다.인삼 이 필요 하기 때문에 여기 서 우 리 는 하나의 종류 로 포장 하기 때문에 마지막 으로@retry()로 바 꿉 니 다.

# retry  ,    3 ,  5 (              ),   
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      (      )
     sleep((random() + 1) * self.wait_secs)
   return None
  return wrapper()
7.다음 에 페이지 를 해석 하 는 방법,즉 parse()를 작성 합 니 다.

#     
 def parse(self, html_page, *, domain='m.sohu.com'):
  soup = BeautifulSoup(html_page, 'lxml')
  url_links = []
  #  body   href     a   
  for a_tag in soup.body.select('a[href]'):
   #       
   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.우 리 는 Spider Thread()의 run 방법 에서

current_url = self.tasks_queue.get()
아래 추가

visited_urls.add(current_url)
클래스 밖 에 하나 더 추가

visited_urls = set()  
8.이제 해당 사이트 주 소 를 캡 처 할 수 있 습 니 다.
 
총결산
위 에서 말 한 것 은 소 편 이 소개 한 python 이 대상 을 대상 으로 다 중 스 레 드 파충류 가 소 후 페이지 의 인 스 턴 스 코드 를 기어 오 르 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기